From ea23d8283ff5a0c80bdb2e499bf356dab36c29e4 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Jan 2017 16:02:58 -0800 Subject: [PATCH 01/45] Introducing the TextureTable in the gpu shader system --- libraries/gpu/src/gpu/TextureTable.slh | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 libraries/gpu/src/gpu/TextureTable.slh diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh new file mode 100644 index 0000000000..1aa727c99d --- /dev/null +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -0,0 +1,29 @@ + +<@if not GPU_TEXTURE_TABLE_SLH@> +<@def GPU_TEXTURE_TABLE_SLH@> + +#ifdef GPU_TEXTURE_TABLE_BINDLESS +#define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8 + +struct TextureTable { + uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; +}; + +#define TextureTable(index) layout (std140) uniform gpu_textureTableBuffer##index { TextureTable _table##index; }; + +#else + +#endif + + + + +<@endif@> From 536ada39735112199080376a9e729d1c2081003a Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Jan 2017 18:38:05 -0800 Subject: [PATCH 02/45] Introducing the TextureTable in the gpu shader system --- .../gpu-gl/src/gpu/gl/GLBackendShader.cpp | 15 +++- libraries/gpu/src/gpu/TextureTable.slh | 8 ++- .../render-utils/src/MaterialTextures.slh | 72 +++++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp index 93c9b0d2ff..557591ffb6 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp @@ -50,6 +50,12 @@ static const std::string stereoVersion { #endif }; +// TextureTable specific defines +static const std::string textureTableVersion { + "#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n" +}; + + // Versions specific of the shader static const std::array VERSION_DEFINES { { "", @@ -64,10 +70,15 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co Shader::CompilationLogs compilationLogs(GLShader::NumVersions); shader.incrementCompilationAttempt(); + bool supportTextureTableBindless = true; + 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 shaderDefines = getBackendShaderHeader() + "\n" + + (supportTextureTableBindless ? textureTableVersion : "\n") + + DOMAIN_DEFINES[shader.getType()] + "\n" + + VERSION_DEFINES[version]; if (handler) { bool retest = true; std::string currentSrc = shaderSource; @@ -89,7 +100,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message); } - if (!compilationLogs[version].compiled) { + if (!compilationLogs[version].compiled) { qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str(); shader.setCompilationLogs(compilationLogs); return nullptr; diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index 1aa727c99d..7859057bdb 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -13,11 +13,13 @@ #ifdef GPU_TEXTURE_TABLE_BINDLESS #define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8 -struct TextureTable { - uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; +struct GPUTextureTable { + uvec2 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; }; -#define TextureTable(index) layout (std140) uniform gpu_textureTableBuffer##index { TextureTable _table##index; }; +#define TextureTable(index, name) layout (std140) uniform gpu_textureTableBuffer { GPUTextureTable name; } + +#define tableTex(name, slot) sampler2D(name._textures[slot]) #else diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 40709b3668..ef77954fad 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -48,6 +48,76 @@ TexMapArray getTexMapArray() { <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@> + + +<@include gpu/TextureTable.slh@> + +TextureTable(0, matTex); + + +<@if withAlbedo@> +#define albedoMap 1 +vec4 fetchAlbedoMap(vec2 uv) { + return texture(tableTex(matTex, albedoMap), uv); +} +<@endif@> + +<@if withRoughness@> +#define roughnessMap 3 +float fetchRoughnessMap(vec2 uv) { + return (texture(tableTex(matTex, roughnessMap), uv).r); +} +<@endif@> + +<@if withNormal@> +#define normalMap 4 +vec3 fetchNormalMap(vec2 uv) { + return texture(tableTex(matTex, normalMap), uv).xyz; +} +<@endif@> + +<@if withMetallic@> +#define metallicMap 2 +float fetchMetallicMap(vec2 uv) { + return (texture(tableTex(matTex, metallicMap), uv).r); +} +<@endif@> + +<@if withEmissive@> +#define emissiveMap 0 +vec3 fetchEmissiveMap(vec2 uv) { + return texture(tableTex(matTex, emissiveMap), uv).rgb; +} +<@endif@> + +<@if withOcclusion@> +#define occlusionMap 5 +float fetchOcclusionMap(vec2 uv) { + return texture(tableTex(matTex, occlusionMap), uv).r; +} +<@endif@> + +<@if withScattering@> +#define scatteringMap 7 +float fetchScatteringMap(vec2 uv) { + float scattering = texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now + return max(((scattering - 0.1) / 0.9), 0.0); + return texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now +} +<@endif@> + + + <@if withAlbedo@> uniform sampler2D albedoMap; vec4 fetchAlbedoMap(vec2 uv) { @@ -101,6 +171,8 @@ float fetchScatteringMap(vec2 uv) { return texture(scatteringMap, uv).r; // boolean scattering for now } <@endif@> +<@endif@> +!> <@endfunc@> From 03aeb7addaa865a2448edd1a361a8e90d7b0b4a4 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 26 Jan 2017 11:04:46 -0800 Subject: [PATCH 03/45] Adding the ubo slot assignment for the resource texture table --- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 6 + libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 444 +++++++++++++++++- libraries/gpu-gl/src/gpu/gl/GLShader.h | 11 + libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 2 +- .../src/gpu/gl45/GL45BackendTexture.cpp | 82 ++++ libraries/gpu/src/gpu/Batch.h | 5 + libraries/gpu/src/gpu/TextureTable.slh | 6 +- .../render-utils/src/MeshPartPayload.cpp | 52 +- 8 files changed, 573 insertions(+), 35 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 18916ac18c..e13bfe8166 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -98,6 +98,12 @@ public: static const int MAX_NUM_RESOURCE_TEXTURES = 16; size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } + // Texture Tables offers 2 dedicated slot (taken from the ubo slots) + static const int MAX_NUM_RESOURCE_TABLE_TEXTURES = 2; + static const int RESOURCE_TABLE_TEXTURE_SLOT_OFFSET = TRANSFORM_CAMERA_SLOT + 1; + size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; } + + // Draw Stage virtual void do_draw(const Batch& batch, size_t paramOffset) = 0; virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 010a7c479c..9c3de94957 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -10,6 +10,447 @@ #include "GLBackend.h" +namespace gpu { + namespace gl { + + 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& textureTables, 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; + } + + loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET); + shaderObject.resourceTextureTableSlot0 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET; + } + loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable1"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1); + shaderObject.resourceTextureTableSlot1 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1; + } + (void)CHECK_GL_ERROR(); + } + } +} + + using namespace gpu; using namespace gpu::gl; @@ -73,8 +514,9 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin Shader::SlotSet uniforms; Shader::SlotSet textures; + Shader::SlotSet textureTables; Shader::SlotSet samplers; - backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); + backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); Shader::SlotSet resourceBuffers; backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index 3259982e93..a5a6a6e72c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -17,8 +17,19 @@ struct ShaderObject { GLuint glprogram { 0 }; GLint transformCameraSlot { -1 }; GLint transformObjectSlot { -1 }; + + GLint resourceTextureTableSlot0 { -1 }; + GLint resourceTextureTableSlot1 { -1 }; }; +int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, + Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, 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); + + class GLShader : public GPUObject { public: static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 1a4b63d35f..098ac11763 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -103,7 +103,7 @@ public: friend class GL45Backend; using PromoteLambda = std::function; - + const uvec4& getHandle(); protected: GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45VariableAllocationTexture(); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 1d415c7ca3..45900a62b6 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -212,6 +212,7 @@ void GL45Texture::syncSampler() const { glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + (void)CHECK_GL_ERROR(); } using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture; @@ -275,6 +276,10 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr& backend, const TextureTable& textureTable, const HandlesArray& handles, bool handlesComplete) + : Parent(backend, textureTable, allocate()), _stamp(textureTable.getStamp()), _handles(handles), _complete(handlesComplete) { + Backend::setGPUObject(textureTable, this); + // FIXME include these in overall buffer storage reporting + glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, &_handles[0], 0); +} + + +GL45TextureTable::~GL45TextureTable() { + if (_id) { + auto backend = _backend.lock(); + if (backend) { + // FIXME include these in overall buffer storage reporting + backend->releaseBuffer(_id, 0); + } + } +} + + +GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureTablePointer) { + const auto& textureTable = *textureTablePointer; + + // Find the target handles + auto textures = textureTable.getTextures(); + bool handlesComplete = true; + GL45TextureTable::HandlesArray handles{}; + for (size_t i = 0; i < textures.size(); ++i) { + auto texture = textures[i]; + if (!texture) { + continue; + } + // FIXME what if we have a non-transferrable texture here? + auto gltexture = (GL45Texture*)syncGPUObject(texture, true); + if (!gltexture) { + handlesComplete = false; + continue; + } + auto handle = gltexture->getHandle(); + memcpy(&handles[i], &handle, sizeof(handle)); + } + + // If the object hasn't been created, or the object definition is out of date, drop and re-create + GL45TextureTable* object = Backend::getGPUObject(textureTable); + + if (!object || object->_stamp != textureTable.getStamp() || !object->_complete || handles != object->_handles) { + object = new GL45TextureTable(shared_from_this(), textureTable, handles, handlesComplete); + } + + return object; +} + +void GL45Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { + auto textureTable = batch._textureTables.get(batch._params[paramOffset]._uint); + auto slot = batch._params[paramOffset + 1]._uint; + GL45TextureTable* glTextureTable = syncGPUObject(textureTable); + if (glTextureTable) { + glBindBufferBase(GL_UNIFORM_BUFFER, slot + GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET, glTextureTable->_id); + } +} diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 79f08ea5cc..a57ee94747 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -30,6 +30,11 @@ 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, }; diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index 7859057bdb..d45c8f819b 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -14,12 +14,12 @@ #define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8 struct GPUTextureTable { - uvec2 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; + uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES]; }; -#define TextureTable(index, name) layout (std140) uniform gpu_textureTableBuffer { GPUTextureTable name; } +#define TextureTable(index, name) layout (std140) uniform gpu_resourceTextureTable##index { GPUTextureTable name; } -#define tableTex(name, slot) sampler2D(name._textures[slot]) +#define tableTex(name, slot) sampler2D(name._textures[slot].xy) #else diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 9655b60a78..2428ec95aa 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -145,6 +145,17 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat } auto textureCache = DependencyManager::get(); + if (!_drawMaterialTextures) { + _drawMaterialTextures = std::make_shared(); + _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, textureCache->getBlueTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); + } batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer()); batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer()); @@ -172,9 +183,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isAlbedoMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, itr->second->getTextureView()); } } @@ -182,11 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isRoughnessMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, itr->second->getTextureView()); } } @@ -194,11 +199,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isNormalMap()) { auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, itr->second->getTextureView()); } } @@ -206,11 +207,11 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isMetallicMap()) { auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, itr->second->getTextureView()); // texcoord are assumed to be the same has albedo } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); } } @@ -218,11 +219,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isOcclusionMap()) { auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, itr->second->getTextureView()); } } @@ -230,11 +227,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isScatteringMap()) { auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, itr->second->getTextureView()); } } @@ -243,17 +236,16 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, itr->second->getTextureView()); } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else if (materialKey.isEmissiveMap()) { auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, itr->second->getTextureView()); } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); } } } From ab5355dbdd91ad8e8e0c5e2c8a803fb79819e610 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Wed, 25 Jan 2017 17:47:33 -0800 Subject: [PATCH 04/45] First pass at bindless textures --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 1 + libraries/gpu-gl/src/gpu/gl/GLBackend.h | 1 + libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 3 ++ .../src/gpu/gl41/GL41BackendTexture.cpp | 3 ++ libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 21 ++++++++ .../src/gpu/gl45/GL45BackendTexture.cpp | 3 +- libraries/gpu/src/gpu/Batch.cpp | 8 +++ libraries/gpu/src/gpu/Batch.h | 4 ++ libraries/gpu/src/gpu/Forward.h | 2 + libraries/gpu/src/gpu/TextureTable.cpp | 48 ++++++++++++++++++ libraries/gpu/src/gpu/TextureTable.h | 42 ++++++++++++++++ .../render-utils/src/MeshPartPayload.cpp | 49 +++++++++---------- libraries/render-utils/src/MeshPartPayload.h | 1 + 13 files changed, 160 insertions(+), 26 deletions(-) create mode 100644 libraries/gpu/src/gpu/TextureTable.cpp create mode 100644 libraries/gpu/src/gpu/TextureTable.h diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index 08bd20be66..3a4c7b4f47 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -99,6 +99,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_setUniformBuffer), (&::gpu::gl::GLBackend::do_setResourceBuffer), (&::gpu::gl::GLBackend::do_setResourceTexture), + (&::gpu::gl::GLBackend::do_setResourceTextureTable), (&::gpu::gl::GLBackend::do_setFramebuffer), (&::gpu::gl::GLBackend::do_clearFramebuffer), diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index e13bfe8166..35aabef48f 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -132,6 +132,7 @@ public: // Resource Stage virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; + virtual void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) = 0; // Pipeline Stage virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 42926fdb1c..1b7882518d 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -157,6 +157,9 @@ protected: void resetInputStage() override; void updateInput() override; + // Resource stage + void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; + // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 925e83bb77..b70730fd98 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -611,3 +611,6 @@ GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr& backend GL41ResourceTexture::~GL41ResourceTexture() { } +void GL41Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { + +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 098ac11763..4fb12fbdb1 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -15,6 +15,7 @@ #include "../gl/GLBackend.h" #include "../gl/GLTexture.h" #include +#include #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 @@ -48,6 +49,21 @@ public: static const std::string GL45_VERSION; const std::string& getVersion() const override { return GL45_VERSION; } + class GL45TextureTable : public GLObject { + static GLuint allocate(); + using Parent = GLObject; + public: + using HandlesArray = std::array; + GL45TextureTable(const std::weak_ptr& backend, const TextureTable& texture, const HandlesArray& newHandles, bool complete); + ~GL45TextureTable(); + + // FIXME instead of making a buffer for each table, there should be a global buffer of all materials + // and we should store an offset into that buffer + const uint32_t _stamp { 0 }; + const HandlesArray _handles; + const bool _complete { false }; + }; + class GL45Texture : public GLTexture { using Parent = GLTexture; friend class GL45Backend; @@ -181,6 +197,8 @@ protected: GLuint getQueryID(const QueryPointer& query) override; GLQuery* syncGPUObject(const Query& query) override; + GL45TextureTable* syncGPUObject(const TextureTablePointer& textureTable); + // Draw Stage void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; @@ -193,6 +211,9 @@ protected: void resetInputStage() override; void updateInput() override; + // Resource stage + void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; + // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 45900a62b6..e3c10928b4 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -20,15 +20,16 @@ #include #include +#include #include "../gl/GLTexelFormat.h" using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; -#define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 + GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { if (!texturePointer) { return nullptr; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index c432e19368..3764a94494 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -59,6 +59,7 @@ Batch::Batch(const Batch& batch_) { _buffers._items.swap(batch._buffers._items); _textures._items.swap(batch._textures._items); + _textureTables._items.swap(batch._textureTables._items); _streamFormats._items.swap(batch._streamFormats._items); _transforms._items.swap(batch._transforms._items); _pipelines._items.swap(batch._pipelines._items); @@ -96,6 +97,7 @@ void Batch::clear() { _data.clear(); _buffers.clear(); _textures.clear(); + _textureTables.clear(); _streamFormats.clear(); _transforms.clear(); _pipelines.clear(); @@ -306,6 +308,12 @@ void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) { _params.emplace_back(slot); } +void Batch::setResourceTextureTable(const TextureTablePointer& textureTable, uint32 slot) { + ADD_COMMAND(setResourceTextureTable); + _params.emplace_back(_textureTables.cache(textureTable)); + _params.emplace_back(slot); +} + void Batch::setResourceTexture(uint32 slot, const TextureView& view) { setResourceTexture(slot, view._texture); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index a57ee94747..8eb769a6fe 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -193,6 +193,7 @@ public: void setResourceTexture(uint32 slot, const TexturePointer& texture); void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView + void setResourceTextureTable(const TextureTablePointer& table, uint32 slot = 0); // Ouput Stage void setFramebuffer(const FramebufferPointer& framebuffer); @@ -304,6 +305,7 @@ public: COMMAND_setUniformBuffer, COMMAND_setResourceBuffer, COMMAND_setResourceTexture, + COMMAND_setResourceTextureTable, COMMAND_setFramebuffer, COMMAND_clearFramebuffer, @@ -422,6 +424,7 @@ public: typedef Cache::Vector BufferCaches; typedef Cache::Vector TextureCaches; + typedef Cache::Vector TextureTableCaches; typedef Cache::Vector StreamFormatCaches; typedef Cache::Vector TransformCaches; typedef Cache::Vector PipelineCaches; @@ -476,6 +479,7 @@ public: BufferCaches _buffers; TextureCaches _textures; + TextureTableCaches _textureTables; StreamFormatCaches _streamFormats; TransformCaches _transforms; PipelineCaches _pipelines; diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index 8100efafaf..987788c29b 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -91,6 +91,8 @@ namespace gpu { using Textures = std::vector; class TextureView; using TextureViews = std::vector; + class TextureTable; + using TextureTablePointer = std::shared_ptr; struct StereoState { bool isStereo() const { diff --git a/libraries/gpu/src/gpu/TextureTable.cpp b/libraries/gpu/src/gpu/TextureTable.cpp new file mode 100644 index 0000000000..17a9e87f3e --- /dev/null +++ b/libraries/gpu/src/gpu/TextureTable.cpp @@ -0,0 +1,48 @@ +// +// Created by Bradley Austin Davis on 2017/01/25 +// 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 "TextureTable.h" +#include "Texture.h" + +using namespace gpu; + +TextureTable::TextureTable() { } + +TextureTable::TextureTable(const std::initializer_list& textures) { + auto max = std::min(COUNT, textures.size()); + auto itr = textures.begin(); + size_t index = 0; + while (itr != textures.end() && index < max) { + setTexture(index, *itr); + ++index; + } +} + +TextureTable::TextureTable(const std::array& textures) : _stamp(1), _textures(textures) { +} + +void TextureTable::setTexture(size_t index, const TexturePointer& texturePointer) { + if (index >= COUNT || _textures[index] == texturePointer) { + return; + } + { + Lock lock(_mutex); + ++_stamp; + _textures[index] = texturePointer; + } +} + +void TextureTable::setTexture(size_t index, const TextureView& textureView) { + setTexture(index, textureView._texture); +} + +TextureTable::Array TextureTable::getTextures() const { + Array result; + Lock lock(_mutex); + result = _textures; + return result; +} diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h new file mode 100644 index 0000000000..7b278bf304 --- /dev/null +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -0,0 +1,42 @@ +// +// Created by Bradley Austin Davis on 2017/01/25 +// 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 +// +#ifndef hifi_gpu_TextureTable_h +#define hifi_gpu_TextureTable_h + +#include "Forward.h" + +#include + +namespace gpu { + +class TextureTable { +public: + static const size_t COUNT = 8; + using Array = std::array; + using Array = std::array; + TextureTable(); + TextureTable(const std::initializer_list& textures); + TextureTable(const std::array& textures); + + // Only for gpu::Context + const GPUObjectPointer gpuObject{}; + + void setTexture(size_t index, const TexturePointer& texturePointer); + void setTexture(size_t index, const TextureView& texturePointer); + + Array getTextures() const; + Stamp getStamp() const { return _stamp; } +private: + mutable Mutex _mutex; + Array _textures; + Stamp _stamp{ 0 }; +}; + +} + +#endif diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2428ec95aa..181eb19c8a 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include "DeferredLightingEffect.h" using namespace render; @@ -144,24 +146,25 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat return; } + + const auto& textureMaps = _drawMaterial->getTextureMaps(); + const auto& materialKey = _drawMaterial->getKey(); auto textureCache = DependencyManager::get(); if (!_drawMaterialTextures) { _drawMaterialTextures = std::make_shared(); - _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, textureCache->getBlueTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, textureCache->getWhiteTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); - _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ALBEDO_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ROUGHNESS_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::NORMAL_MAP, textureCache->getBlueTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::OCCLUSION_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::SCATTERING_MAP, textureCache->getWhiteTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); } batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer()); batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer()); - - const auto& materialKey = _drawMaterial->getKey(); - const auto& textureMaps = _drawMaterial->getTextureMaps(); + batch.setResourceTextureTable(_drawMaterialTextures); int numUnlit = 0; if (materialKey.isUnlit()) { @@ -183,7 +186,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isAlbedoMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ALBEDO_MAP, itr->second->getTextureView()); } } @@ -191,7 +194,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isRoughnessMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::ROUGHNESS_MAP, itr->second->getTextureView()); } } @@ -199,7 +202,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isNormalMap()) { auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::NORMAL_MAP, itr->second->getTextureView()); } } @@ -207,11 +210,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isMetallicMap()) { auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - _drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::METALLIC_MAP, itr->second->getTextureView()); } } @@ -219,7 +218,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isOcclusionMap()) { auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::OCCLUSION_MAP, itr->second->getTextureView()); } } @@ -227,7 +226,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat if (materialKey.isScatteringMap()) { auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::SCATTERING_MAP, itr->second->getTextureView()); } } @@ -236,16 +235,16 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::LIGHTMAP_MAP, itr->second->getTextureView()); } else { - _drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture()); } } else if (materialKey.isEmissiveMap()) { auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); if (itr != textureMaps.end() && itr->second->isDefined()) { - _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, itr->second->getTextureView()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::EMISSIVE_MAP, itr->second->getTextureView()); } else { - _drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); + _drawMaterialTextures->setTexture(graphics::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture()); } } } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 21f9dc2e68..51bc7f39e0 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -67,6 +67,7 @@ public: std::shared_ptr _drawMaterial; graphics::Mesh::Part _drawPart; + mutable gpu::TextureTablePointer _drawMaterialTextures; size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; } size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; } From 5139f3f50328c0299801906ba435d5e1528c72f8 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Mon, 5 Mar 2018 14:15:50 -0800 Subject: [PATCH 05/45] Update repo script with marketplace script --- scripts/tutorials/entity_scripts/sit.js | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 70456ea493..9de65d7037 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -12,9 +12,9 @@ Script.include("/~/system/libraries/utils.js"); if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position){ - position = position || 0; - return this.substr(position, searchString.length) === searchString; - }; + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; } var SETTING_KEY = "com.highfidelity.avatar.isSitting"; @@ -122,20 +122,10 @@ this.rolesToOverride = function() { return MyAvatar.getAnimationRoles().filter(function(role) { - return !(role.startsWith("right") || role.startsWith("left")); + return !(role.startsWith("right") || role.startsWith("left")); }); } - // Handler for user changing the avatar model while sitting. There's currently an issue with changing avatar models while override role animations are applied, - // so to avoid that problem, re-apply the role overrides once the model has finished changing. - this.modelURLChangeFinished = function () { - print("Sitter's model has FINISHED changing. Reapply anim role overrides."); - var roles = this.rolesToOverride(); - for (i in roles) { - MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); - } - } - this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); @@ -174,14 +164,12 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); - MyAvatar.onLoadComplete.connect(this, this.modelURLChangeFinished); } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); - MyAvatar.onLoadComplete.disconnect(this, this.modelURLChangeFinished); if (MyAvatar.sessionUUID === this.getSeatUser()) { this.setSeatUser(null); @@ -343,7 +331,7 @@ } this.cleanupOverlay(); } - + this.clickDownOnEntity = function (id, event) { if (isInEditMode()) { return; @@ -352,4 +340,4 @@ this.sitDown(); } } -}); +}); \ No newline at end of file From b7d0260a17654dd79854e5b65058b2cd74c6115f Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 8 Feb 2018 14:05:21 -0800 Subject: [PATCH 06/45] Fix the uniform target for bindless --- libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 444 +----------------- libraries/gpu-gl/src/gpu/gl/GLShader.h | 9 - .../src/gpu/gl41/GL41BackendTexture.cpp | 4 - libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 84 +++- .../gpu-gl/src/gpu/gl45/GL45BackendShader.cpp | 5 + .../src/gpu/gl45/GL45BackendTexture.cpp | 183 ++++++-- .../gpu/gl45/GL45BackendVariableTexture.cpp | 19 +- libraries/gpu/src/gpu/Texture.h | 34 +- libraries/gpu/src/gpu/TextureTable.h | 1 - libraries/gpu/src/gpu/TextureTable.slh | 3 - 10 files changed, 259 insertions(+), 527 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 9c3de94957..7a26642024 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -10,447 +10,6 @@ #include "GLBackend.h" -namespace gpu { - namespace gl { - - 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& textureTables, 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; - } - - loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET); - shaderObject.resourceTextureTableSlot0 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET; - } - loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable1"); - if (loc >= 0) { - glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1); - shaderObject.resourceTextureTableSlot1 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1; - } - (void)CHECK_GL_ERROR(); - } - } -} - - using namespace gpu; using namespace gpu::gl; @@ -516,7 +75,8 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin Shader::SlotSet textures; Shader::SlotSet textureTables; Shader::SlotSet samplers; - backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); + //backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); + backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); Shader::SlotSet resourceBuffers; backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers); diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index a5a6a6e72c..b2a1f189a2 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -17,19 +17,10 @@ struct ShaderObject { GLuint glprogram { 0 }; GLint transformCameraSlot { -1 }; GLint transformObjectSlot { -1 }; - GLint resourceTextureTableSlot0 { -1 }; GLint resourceTextureTableSlot1 { -1 }; }; -int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, - Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, 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); - - class GLShader : public GPUObject { public: static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr); diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index b70730fd98..495f11e4a8 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -167,7 +167,6 @@ void GL41Texture::syncSampler() const { glTexParameteri(_target, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); - glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); @@ -206,9 +205,6 @@ void GL41FixedAllocationTexture::allocateStorage() const { void GL41FixedAllocationTexture::syncSampler() const { Parent::syncSampler(); const Sampler& sampler = _gpuObject.getSampler(); - auto baseMip = std::max(sampler.getMipOffset(), sampler.getMinMip()); - - glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, baseMip); glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip())); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 4fb12fbdb1..d733b38a2f 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -19,6 +19,7 @@ #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 +#define GPU_BINDLESS_TEXTURES 1 namespace gpu { namespace gl45 { @@ -49,21 +50,6 @@ public: static const std::string GL45_VERSION; const std::string& getVersion() const override { return GL45_VERSION; } - class GL45TextureTable : public GLObject { - static GLuint allocate(); - using Parent = GLObject; - public: - using HandlesArray = std::array; - GL45TextureTable(const std::weak_ptr& backend, const TextureTable& texture, const HandlesArray& newHandles, bool complete); - ~GL45TextureTable(); - - // FIXME instead of making a buffer for each table, there should be a global buffer of all materials - // and we should store an offset into that buffer - const uint32_t _stamp { 0 }; - const HandlesArray _handles; - const bool _complete { false }; - }; - class GL45Texture : public GLTexture { using Parent = GLTexture; friend class GL45Backend; @@ -73,8 +59,72 @@ public: void generateMips() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void syncSampler() const override; + + bool isBindless() const { +#if GPU_BINDLESS_TEXTURES + return _bindless.operator bool(); +#else + return false; +#endif + } + +#if GPU_BINDLESS_TEXTURES + struct Bindless { + uint64_t handle{ 0 }; + uint32_t minMip{ 0 }; + uint32_t sampler{ 0 }; + + operator bool() const { + return handle != 0; + } + }; + + virtual const Bindless& getBindless() const; + void releaseBindless() const; + void recreateBindless() const; + virtual uint16 getMinMip() const = 0; + + + private: + class InvalidSampler : public Sampler { + public: + InvalidSampler() { + _desc._borderColor = vec4(-1.0f); + } + + operator const Sampler&() const { + return *this; + } + }; + + static const Sampler INVALID_SAMPLER; + // This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w + mutable Sampler _cachedSampler{ INVALID_SAMPLER }; + + mutable Bindless _bindless; + +#endif }; +#if GPU_BINDLESS_TEXTURES + class GL45TextureTable : public GLObject { + static GLuint allocate(); + using Parent = GLObject; + public: + using BindlessArray = std::array; + + GL45TextureTable(const std::weak_ptr& backend, const TextureTable& texture); + ~GL45TextureTable(); + + void update(const BindlessArray& newHandles); + + // FIXME instead of making a buffer for each table, there should be a global buffer of all materials + // and we should store an offset into that buffer + BindlessArray _handles; + }; +#endif + + // // Textures that have fixed allocation sizes and cannot be managed at runtime // @@ -89,6 +139,8 @@ public: protected: Size size() const override { return _size; } + uint16 getMinMip() const override { return 0; } + void allocateStorage() const; void syncSampler() const override; const Size _size { 0 }; @@ -125,6 +177,8 @@ public: ~GL45VariableAllocationTexture(); Size size() const override { return _size; } + uint16 getMinMip() const override { return _populatedMip; } + virtual const Bindless& getBindless() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void copyTextureMipsInGPUMem(GLuint srcId, GLuint destId, uint16_t srcMipOffset, uint16_t destMipOffset, uint16_t populatedMips) override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp index c2490524ae..9c973c9a6a 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp @@ -165,6 +165,11 @@ void GL45Backend::makeProgramBindings(ShaderObject& shaderObject) { shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; } + loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0"); + if (loc >= 0) { + glUniformBlockBinding(glprogram, loc, RESOURCE_TABLE_TEXTURE_SLOT_OFFSET); + } + (void)CHECK_GL_ERROR(); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index e3c10928b4..d33afc0e67 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "../gl/GLTexelFormat.h" @@ -29,6 +30,10 @@ using namespace gpu::gl45; #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 +#pragma optimize("", off) + +#define FORCE_STRICT_TEXTURE 0 +#define ENABLE_SPARSE_TEXTURE 0 GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { if (!texturePointer) { @@ -52,14 +57,18 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { object = new GL45AttachmentTexture(shared_from_this(), texture); break; +#if FORCE_STRICT_TEXTURE + case TextureUsageType::RESOURCE: +#endif case TextureUsageType::STRICT_RESOURCE: qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str(); object = new GL45StrictResourceTexture(shared_from_this(), texture); break; +#if !FORCE_STRICT_TEXTURE case TextureUsageType::RESOURCE: { if (GL45VariableAllocationTexture::_frameTexturesCreated < MAX_RESOURCE_TEXTURES_PER_FRAME) { -#if 0 +#if ENABLE_SPARSE_TEXTURE if (isTextureManagementSparseEnabled() && GL45Texture::isSparseEligible(texture)) { object = new GL45SparseResourceTexture(shared_from_this(), texture); } else { @@ -77,7 +86,7 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { } break; } - +#endif default: Q_UNREACHABLE(); } @@ -115,6 +124,50 @@ void GL45Backend::initTextureManagementStage() { using GL45Texture = GL45Backend::GL45Texture; + +class GLSamplerCache { +public: + GLuint getGLSampler(const Sampler& sampler) { + if (0 == _samplerCache.count(sampler)) { + GLuint result = 0; + glGenSamplers(1, &result); + const auto& fm = GLTexture::FILTER_MODES[sampler.getFilter()]; + glSamplerParameteri(result, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glSamplerParameteri(result, GL_TEXTURE_MAG_FILTER, fm.magFilter); + if (sampler.doComparison()) { + glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glSamplerParameteri(result, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); + } else { + glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + glSamplerParameteri(result, GL_TEXTURE_WRAP_S, GLTexture::WRAP_MODES[sampler.getWrapModeU()]); + glSamplerParameteri(result, GL_TEXTURE_WRAP_T, GLTexture::WRAP_MODES[sampler.getWrapModeV()]); + glSamplerParameteri(result, GL_TEXTURE_WRAP_R, GLTexture::WRAP_MODES[sampler.getWrapModeW()]); + + glSamplerParameterf(result, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + glSamplerParameterfv(result, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + + glSamplerParameterf(result, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); + glSamplerParameterf(result, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + _samplerCache[sampler] = result; + return result; + } + + return _samplerCache[sampler]; + } + + void releaseGLSampler(GLuint sampler) { + // NO OP + } + +private: + std::unordered_map _samplerCache; +}; + +static GLSamplerCache SAMPLER_CACHE; +const Sampler GL45Texture::INVALID_SAMPLER = GL45Texture::InvalidSampler(); + GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture) : GLTexture(backend, texture, allocate(texture)) { } @@ -122,10 +175,10 @@ GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& GLuint GL45Texture::allocate(const Texture& texture) { GLuint result; glCreateTextures(getGLTextureType(texture), 1, &result); -#ifdef DEBUG - auto source = texture.source(); - glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data()); -#endif + if (::gl::Context::enableDebugLogger()) { + auto source = texture.source(); + glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data()); + } return result; } @@ -190,32 +243,69 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const return amountCopied; } -void GL45Texture::syncSampler() const { - const Sampler& sampler = _gpuObject.getSampler(); - - const auto& fm = FILTER_MODES[sampler.getFilter()]; - glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); - glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); - - if (sampler.doComparison()) { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); - glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); - } else { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); +void GL45Texture::releaseBindless() const { + // Release the old handler + SAMPLER_CACHE.releaseGLSampler(_bindless.sampler); + glMakeTextureHandleNonResidentARB(_bindless.handle); + _bindless = Bindless(); +} + +void GL45Texture::recreateBindless() const { + if (isBindless()) { + releaseBindless(); } - glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + _bindless.sampler = SAMPLER_CACHE.getGLSampler(_cachedSampler); + _bindless.handle = glGetTextureSamplerHandleARB(_id, _bindless.sampler); + glMakeTextureHandleResidentARB(_bindless.handle); +} - glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); +const GL45Texture::Bindless& GL45Texture::getBindless() const { + if (!_bindless) { + recreateBindless(); + } + _bindless.minMip = getMinMip(); + return _bindless; +} - glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); - glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); +void GL45Texture::syncSampler() const { + const Sampler& sampler = _gpuObject.getSampler(); + bool samplerChanged = _cachedSampler != sampler; + if (samplerChanged) { + _cachedSampler = sampler; + } + + if (isBindless()) { + if (samplerChanged) { + recreateBindless(); + } + } else if (samplerChanged) { + const auto& fm = FILTER_MODES[sampler.getFilter()]; + glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + if (sampler.doComparison()) { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); + } else { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + + glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + + glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); + glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + } (void)CHECK_GL_ERROR(); } +// Fixed allocation textures, used for strict resources & framebuffer attachments + using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture; GL45FixedAllocationTexture::GL45FixedAllocationTexture(const std::weak_ptr& backend, const Texture& texture) : GL45Texture(backend, texture), _size(texture.evalTotalSize()) { @@ -240,8 +330,6 @@ void GL45FixedAllocationTexture::allocateStorage() const { void GL45FixedAllocationTexture::syncSampler() const { Parent::syncSampler(); const Sampler& sampler = _gpuObject.getSampler(); - auto baseMip = std::max(sampler.getMipOffset(), sampler.getMinMip()); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip); glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); } @@ -280,7 +368,6 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr& backend, const TextureTable& textureTable, const HandlesArray& handles, bool handlesComplete) - : Parent(backend, textureTable, allocate()), _stamp(textureTable.getStamp()), _handles(handles), _complete(handlesComplete) { +GL45TextureTable::GL45TextureTable(const std::weak_ptr& backend, const TextureTable& textureTable) + : Parent(backend, textureTable, allocate()){ Backend::setGPUObject(textureTable, this); // FIXME include these in overall buffer storage reporting - glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, &_handles[0], 0); + glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, nullptr, GL_DYNAMIC_STORAGE_BIT); } +void GL45TextureTable::update(const BindlessArray& handles) { + if (_handles != handles) { + _handles = handles; + // FIXME include these in overall buffer storage reporting + // FIXME use a single shared buffer for bindless data + glNamedBufferSubData(_id, 0, sizeof(GL45Texture::Bindless) * TextureTable::COUNT, &_handles[0]); + } +} GL45TextureTable::~GL45TextureTable() { if (_id) { @@ -324,36 +410,33 @@ GL45TextureTable::~GL45TextureTable() { } } - GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureTablePointer) { const auto& textureTable = *textureTablePointer; // Find the target handles auto textures = textureTable.getTextures(); - bool handlesComplete = true; - GL45TextureTable::HandlesArray handles{}; + GL45TextureTable::BindlessArray handles{}; for (size_t i = 0; i < textures.size(); ++i) { auto texture = textures[i]; if (!texture) { continue; } // FIXME what if we have a non-transferrable texture here? - auto gltexture = (GL45Texture*)syncGPUObject(texture, true); + auto gltexture = (GL45Texture*)syncGPUObject(texture); if (!gltexture) { - handlesComplete = false; continue; } - auto handle = gltexture->getHandle(); - memcpy(&handles[i], &handle, sizeof(handle)); + handles[i] = gltexture->getBindless(); } // If the object hasn't been created, or the object definition is out of date, drop and re-create GL45TextureTable* object = Backend::getGPUObject(textureTable); - if (!object || object->_stamp != textureTable.getStamp() || !object->_complete || handles != object->_handles) { - object = new GL45TextureTable(shared_from_this(), textureTable, handles, handlesComplete); + if (!object) { + object = new GL45TextureTable(shared_from_this(), textureTable); } + object->update(handles); return object; } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 0f1de0f868..ab5577940c 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -27,6 +27,7 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; +using GL45Texture = GL45Backend::GL45Texture; using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture; GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture) : GL45Texture(backend, texture) { @@ -40,6 +41,12 @@ GL45VariableAllocationTexture::~GL45VariableAllocationTexture() { Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0); } +const GL45Texture::Bindless& GL45VariableAllocationTexture::getBindless() const { + auto& result = Parent::getBindless(); + _bindless.minMip = _populatedMip - _allocatedMip; + return result; +} + Size GL45VariableAllocationTexture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const { Size amountCopied = 0; amountCopied = Parent::copyMipFaceLinesFromTexture(mip, face, size, yOffset, internalFormat, format, type, sourceSize, sourcePointer); @@ -127,7 +134,9 @@ Size GL45ResourceTexture::copyMipsFromTexture() { void GL45ResourceTexture::syncSampler() const { Parent::syncSampler(); - glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); + if (!isBindless()) { + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); + } } void GL45ResourceTexture::promote() { @@ -137,6 +146,10 @@ void GL45ResourceTexture::promote() { uint16_t targetAllocatedMip = _allocatedMip - std::min(_allocatedMip, 2); targetAllocatedMip = std::max(_minAllocatedMip, targetAllocatedMip); + if (isBindless()) { + releaseBindless(); + } + GLuint oldId = _id; auto oldSize = _size; uint16_t oldAllocatedMip = _allocatedMip; @@ -170,6 +183,10 @@ void GL45ResourceTexture::demote() { auto oldSize = _size; auto oldPopulatedMip = _populatedMip; + if (isBindless()) { + releaseBindless(); + } + // allocate new texture const_cast(_id) = allocate(_gpuObject); uint16_t oldAllocatedMip = _allocatedMip; diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index ad3dc5fada..096d6368f8 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -17,8 +17,10 @@ #include #include +#include #include #include +#include #include "Forward.h" #include "Resource.h" #include "Metric.h" @@ -126,12 +128,23 @@ public: uint8 _wrapModeV = WRAP_REPEAT; uint8 _wrapModeW = WRAP_REPEAT; - uint8 _mipOffset = 0; uint8 _minMip = 0; uint8 _maxMip = MAX_MIP_LEVEL; Desc() {} Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {} + + bool operator==(const Desc& other) const { + return _borderColor == other._borderColor && + _maxAnisotropy == other._maxAnisotropy && + _filter == other._filter && + _comparisonFunc == other._comparisonFunc && + _wrapModeU == other._wrapModeU && + _wrapModeV == other._wrapModeV && + _wrapModeW == other._wrapModeW && + _minMip == other._minMip && + _maxMip == other._maxMip; + } }; Sampler() {} @@ -151,11 +164,17 @@ public: ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); } bool doComparison() const { return getComparisonFunction() != ALWAYS; } - uint8 getMipOffset() const { return _desc._mipOffset; } uint8 getMinMip() const { return _desc._minMip; } uint8 getMaxMip() const { return _desc._maxMip; } const Desc& getDesc() const { return _desc; } + + bool operator==(const Sampler& other) const { + return _desc == other._desc; + } + bool operator!=(const Sampler& other) const { + return !(*this == other); + } protected: Desc _desc; }; @@ -667,6 +686,17 @@ typedef std::shared_ptr< TextureSource > TextureSourcePointer; }; +namespace std { + template<> struct hash { + size_t operator()(const gpu::Sampler& sampler) const noexcept { + size_t result = 0; + const auto& desc = sampler.getDesc(); + hash_combine(result, desc._comparisonFunc, desc._filter, desc._maxAnisotropy, desc._maxMip, desc._minMip, desc._wrapModeU, desc._wrapModeV, desc._wrapModeW); + return result; + } + }; +} + Q_DECLARE_METATYPE(gpu::TexturePointer) #endif diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h index 7b278bf304..4307e60adb 100644 --- a/libraries/gpu/src/gpu/TextureTable.h +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -18,7 +18,6 @@ class TextureTable { public: static const size_t COUNT = 8; using Array = std::array; - using Array = std::array; TextureTable(); TextureTable(const std::initializer_list& textures); TextureTable(const std::array& textures); diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index d45c8f819b..1b83f4d622 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -25,7 +25,4 @@ struct GPUTextureTable { #endif - - - <@endif@> From f9605cffb127cc1870c132ec17907dbcc1770c1d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 6 Mar 2018 11:20:54 -0800 Subject: [PATCH 07/45] Target available mip --- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 18 ++++++++++-------- libraries/gpu/src/gpu/TextureTable.slh | 10 ++++++++++ libraries/gpu/src/gpu/Texture_ktx.cpp | 4 +++- .../render-utils/src/MaterialTextures.slh | 14 +++++++------- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index d33afc0e67..f02615c5c7 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -253,6 +253,9 @@ void GL45Texture::releaseBindless() const { void GL45Texture::recreateBindless() const { if (isBindless()) { releaseBindless(); + } else { + // Once a texture is about to become bindless, it's base mip level MUST be set to 0 + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); } _bindless.sampler = SAMPLER_CACHE.getGLSampler(_cachedSampler); @@ -270,16 +273,15 @@ const GL45Texture::Bindless& GL45Texture::getBindless() const { void GL45Texture::syncSampler() const { const Sampler& sampler = _gpuObject.getSampler(); - bool samplerChanged = _cachedSampler != sampler; - if (samplerChanged) { - _cachedSampler = sampler; - } + if (_cachedSampler == sampler) { + return; + } + + _cachedSampler = sampler; if (isBindless()) { - if (samplerChanged) { - recreateBindless(); - } - } else if (samplerChanged) { + recreateBindless(); + } else { const auto& fm = FILTER_MODES[sampler.getFilter()]; glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); diff --git a/libraries/gpu/src/gpu/TextureTable.slh b/libraries/gpu/src/gpu/TextureTable.slh index 1b83f4d622..f2d89e753b 100644 --- a/libraries/gpu/src/gpu/TextureTable.slh +++ b/libraries/gpu/src/gpu/TextureTable.slh @@ -20,7 +20,17 @@ struct GPUTextureTable { #define TextureTable(index, name) layout (std140) uniform gpu_resourceTextureTable##index { GPUTextureTable name; } #define tableTex(name, slot) sampler2D(name._textures[slot].xy) +#define tableTexMinLod(name, slot) float(name._textures[slot].z) +#define tableTexValue(name, slot, uv) \ + tableTexValueLod(tableTex(matTex, albedoMap), tableTexMinLod(matTex, albedoMap), uv) + +vec4 tableTexValueLod(sampler2D sampler, float minLod, vec2 uv) { + float queryLod = textureQueryLod(sampler, uv).x; + queryLod = max(minLod, queryLod); + return textureLod(sampler, uv, queryLod); +} + #else #endif diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 754bdca445..803acbd961 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -504,6 +504,8 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) { gpuktxKeyValue._usage = Texture::Usage::Builder().withColor().withAlpha().build(); } + auto samplerDesc = gpuktxKeyValue._samplerDesc; + samplerDesc._maxMip = gpu::Sampler::MAX_MIP_LEVEL; auto texture = create(gpuktxKeyValue._usageType, type, texelFormat, @@ -513,7 +515,7 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) { 1, // num Samples header.getNumberOfSlices(), header.getNumberOfLevels(), - gpuktxKeyValue._samplerDesc); + samplerDesc); texture->setUsage(gpuktxKeyValue._usage); // Assing the mips availables diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index ef77954fad..72db15aea9 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -67,42 +67,42 @@ SCATTERING_MAP, <@if withAlbedo@> #define albedoMap 1 vec4 fetchAlbedoMap(vec2 uv) { - return texture(tableTex(matTex, albedoMap), uv); + return tableTexValue(matTex, albedoMap, uv); } <@endif@> <@if withRoughness@> #define roughnessMap 3 float fetchRoughnessMap(vec2 uv) { - return (texture(tableTex(matTex, roughnessMap), uv).r); + return tableTexValue(matTex, roughnessMap, uv).r; } <@endif@> <@if withNormal@> #define normalMap 4 vec3 fetchNormalMap(vec2 uv) { - return texture(tableTex(matTex, normalMap), uv).xyz; + return tableTexValue(matTex, normalMap, uv).xyz; } <@endif@> <@if withMetallic@> #define metallicMap 2 float fetchMetallicMap(vec2 uv) { - return (texture(tableTex(matTex, metallicMap), uv).r); + return tableTexValue(matTex, metallicMap, uv).r; } <@endif@> <@if withEmissive@> #define emissiveMap 0 vec3 fetchEmissiveMap(vec2 uv) { - return texture(tableTex(matTex, emissiveMap), uv).rgb; + return tableTexValue(matTex, emissiveMap, uv).rgb; } <@endif@> <@if withOcclusion@> #define occlusionMap 5 float fetchOcclusionMap(vec2 uv) { - return texture(tableTex(matTex, occlusionMap), uv).r; + return tableTexValue(matTex, occlusionMap, uv).r; } <@endif@> @@ -111,7 +111,7 @@ float fetchOcclusionMap(vec2 uv) { float fetchScatteringMap(vec2 uv) { float scattering = texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now return max(((scattering - 0.1) / 0.9), 0.0); - return texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now + return tableTexValue(matTex, scatteringMap, uv).r; // boolean scattering for now } <@endif@> From bf1e5f1dbc816e9868094d5d94b2bc62737cde79 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 7 Mar 2018 16:00:14 -0800 Subject: [PATCH 08/45] Fix varaible allocated bindless textures --- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 10 +++++++++- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 3 ++- .../src/gpu/gl45/GL45BackendVariableTexture.cpp | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index d733b38a2f..e4a96349a9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -74,6 +74,14 @@ public: uint32_t minMip{ 0 }; uint32_t sampler{ 0 }; + bool operator==(const Bindless& other) const { + return handle == other.handle && minMip == other.minMip && sampler == other.sampler; + } + + bool operator!=(const Bindless& other) const { + return !(*this == other); + } + operator bool() const { return handle != 0; } @@ -177,7 +185,7 @@ public: ~GL45VariableAllocationTexture(); Size size() const override { return _size; } - uint16 getMinMip() const override { return _populatedMip; } + uint16 getMinMip() const override { return _populatedMip - _allocatedMip; } virtual const Bindless& getBindless() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index f02615c5c7..a87999781a 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -249,7 +249,7 @@ void GL45Texture::releaseBindless() const { glMakeTextureHandleNonResidentARB(_bindless.handle); _bindless = Bindless(); } - + void GL45Texture::recreateBindless() const { if (isBindless()) { releaseBindless(); @@ -439,6 +439,7 @@ GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureT } object->update(handles); + return object; } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index ab5577940c..293b34fb39 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -146,7 +146,8 @@ void GL45ResourceTexture::promote() { uint16_t targetAllocatedMip = _allocatedMip - std::min(_allocatedMip, 2); targetAllocatedMip = std::max(_minAllocatedMip, targetAllocatedMip); - if (isBindless()) { + bool bindless = isBindless(); + if (bindless) { releaseBindless(); } @@ -163,6 +164,10 @@ void GL45ResourceTexture::promote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); + if (bindless) { + getBindless(); + } + // destroy the old texture glDeleteTextures(1, &oldId); @@ -183,7 +188,8 @@ void GL45ResourceTexture::demote() { auto oldSize = _size; auto oldPopulatedMip = _populatedMip; - if (isBindless()) { + bool bindless = isBindless(); + if (bindless) { releaseBindless(); } @@ -196,6 +202,10 @@ void GL45ResourceTexture::demote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); + if (bindless) { + getBindless(); + } + // destroy the old texture glDeleteTextures(1, &oldId); From d858d3452336a2fbba9612a6b8cd7cb594be0c3d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 7 Mar 2018 17:27:47 -0800 Subject: [PATCH 09/45] Update material binding --- libraries/graphics/src/graphics/Material.h | 11 +++ .../render-utils/src/MaterialTextures.slh | 25 +++-- .../render-utils/src/RenderPipelines.cpp | 96 +++++++++++++++++++ 3 files changed, 119 insertions(+), 13 deletions(-) diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 632cf99391..d31a0cbd31 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -20,9 +20,12 @@ #include #include +#include class Transform; +#define USE_BINDLESS_TEXTURES 1 + namespace graphics { class TextureMap; @@ -360,6 +363,11 @@ public: void setModel(const std::string& model) { _model = model; } +#if USE_BINDLESS_TEXTURES + const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } + void setTextureTable(const gpu::TextureTablePointer& textureTable) { _textureTable = textureTable; } +#endif + protected: std::string _name { "" }; @@ -367,6 +375,9 @@ private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _texMapArrayBuffer; +#if USE_BINDLESS_TEXTURES + mutable gpu::TextureTablePointer _textureTable; +#endif TextureMaps _textureMaps; diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 594fb5c380..6c335353fd 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -54,32 +54,31 @@ TexMapArray getTexMapArray() { TextureTable(0, matTex); <@if withAlbedo@> -#define albedoMap 1 +#define albedoMap 0 vec4 fetchAlbedoMap(vec2 uv) { return tableTexValue(matTex, albedoMap, uv); } <@endif@> <@if withRoughness@> -#define roughnessMap 3 +#define roughnessMap 4 float fetchRoughnessMap(vec2 uv) { return tableTexValue(matTex, roughnessMap, uv).r; } <@endif@> <@if withNormal@> -#define normalMap 4 +#define normalMap 1 vec3 fetchNormalMap(vec2 uv) { return tableTexValue(matTex, normalMap, uv).xyz; } @@ -93,7 +92,7 @@ float fetchMetallicMap(vec2 uv) { <@endif@> <@if withEmissive@> -#define emissiveMap 0 +#define emissiveMap 3 vec3 fetchEmissiveMap(vec2 uv) { return tableTexValue(matTex, emissiveMap, uv).rgb; } @@ -107,7 +106,7 @@ float fetchOcclusionMap(vec2 uv) { <@endif@> <@if withScattering@> -#define scatteringMap 7 +#define scatteringMap 6 float fetchScatteringMap(vec2 uv) { float scattering = texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now return max(((scattering - 0.1) / 0.9), 0.0); diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index aca8439547..8165e09754 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -612,6 +612,21 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) { #include "RenderPipelines.h" #include +#if USE_BINDLESS_TEXTURES +gpu::TextureTablePointer makeTextureTable() { + auto textureCache = DependencyManager::get(); + auto textureTable = std::make_shared(); + textureTable->setTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::ROUGHNESS, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::NORMAL, textureCache->getBlueTexture()); + textureTable->setTexture(ShapePipeline::Slot::METALLIC, textureCache->getBlackTexture()); + textureTable->setTexture(ShapePipeline::Slot::OCCLUSION, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::SCATTERING, textureCache->getWhiteTexture()); + textureTable->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + return textureTable; +} +#endif + void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) { if (!material) { return; @@ -630,6 +645,86 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc numUnlit++; } +#if USE_BINDLESS_TEXTURES + if (!material->getTextureTable()) { + material->setTextureTable(makeTextureTable()); + } + + batch.setResourceTextureTable(material->getTextureTable()); + if (!enableTextures) { + return; + } + + const auto& drawMaterialTextures = material->getTextureTable(); + + // Albedo + if (materialKey.isAlbedoMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); + } + } + + // Roughness map + if (materialKey.isRoughnessMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, itr->second->getTextureView()); + } + } + + // Normal map + if (materialKey.isNormalMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, itr->second->getTextureView()); + } + } + + // Metallic map + if (materialKey.isMetallicMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, itr->second->getTextureView()); + } + } + + // Occlusion map + if (materialKey.isOcclusionMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, itr->second->getTextureView()); + } + } + + // Scattering map + if (materialKey.isScatteringMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, itr->second->getTextureView()); + } + } + + // Emissive / Lightmap + if (materialKey.isLightmapMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); + + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); + } + } else if (materialKey.isEmissiveMap()) { + auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); + if (itr != textureMaps.end() && itr->second->isDefined()) { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); + } + } + + +#else if (!enableTextures) { batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); @@ -729,4 +824,5 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); } } +#endif } From 09996e0b65c14829283380492e8900bc894aaa6b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 8 Mar 2018 15:54:50 -0800 Subject: [PATCH 10/45] Bindless texture work cleanup --- libraries/gpu-gl/src/gpu/gl/GLBackend.h | 13 +- .../gpu-gl/src/gpu/gl/GLBackendPipeline.cpp | 27 ++- .../gpu-gl/src/gpu/gl/GLBackendShader.cpp | 9 +- libraries/gpu-gl/src/gpu/gl/GLShader.cpp | 2 - libraries/gpu-gl/src/gpu/gl/GLShader.h | 2 - libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 3 - .../src/gpu/gl41/GL41BackendTexture.cpp | 4 - libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 36 ++-- .../src/gpu/gl45/GL45BackendTexture.cpp | 65 ++++--- .../gpu/gl45/GL45BackendVariableTexture.cpp | 21 ++- libraries/gpu/src/gpu/Batch.cpp | 8 +- libraries/gpu/src/gpu/Batch.h | 10 +- libraries/gpu/src/gpu/TextureTable.cpp | 7 +- libraries/gpu/src/gpu/TextureTable.h | 1 + libraries/graphics/src/graphics/Material.h | 9 +- .../render-utils/src/MaterialTextures.slh | 11 +- .../render-utils/src/MeshPartPayload.cpp | 2 - .../render-utils/src/RenderPipelines.cpp | 159 +++--------------- libraries/render-utils/src/RenderPipelines.h | 2 +- 19 files changed, 152 insertions(+), 239 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.h b/libraries/gpu-gl/src/gpu/gl/GLBackend.h index 35aabef48f..f0f7093845 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.h @@ -36,7 +36,6 @@ //#define GPU_STEREO_TECHNIQUE_DOUBLED_SMARTER #define GPU_STEREO_TECHNIQUE_INSTANCED - // Let these be configured by the one define picked above #ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE #define GPU_STEREO_DRAWCALL_DOUBLED @@ -52,6 +51,8 @@ #define GPU_STEREO_CAMERA_BUFFER #endif +#define GPU_BINDLESS_TEXTURES 0 + namespace gpu { namespace gl { class GLBackend : public Backend, public std::enable_shared_from_this { @@ -132,7 +133,7 @@ public: // Resource Stage virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; - virtual void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) = 0; + virtual void do_setResourceTextureTable(const Batch& batch, size_t paramOffset); // Pipeline Stage virtual void do_setPipeline(const Batch& batch, size_t paramOffset) final; @@ -229,6 +230,10 @@ protected: void recycle() const override; + // FIXME instead of a single flag, create a features struct similar to + // https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkPhysicalDeviceFeatures.html + virtual bool supportsBindless() const { return false; } + static const size_t INVALID_OFFSET = (size_t)-1; bool _inRenderTransferPass { false }; int32_t _uboAlignment { 0 }; @@ -383,6 +388,10 @@ protected: virtual bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) = 0; virtual void releaseResourceBuffer(uint32_t slot) = 0; + // Helper function that provides common code used by do_setResourceTexture and + // do_setResourceTextureTable (in non-bindless mode) + void bindResourceTexture(uint32_t slot, const TexturePointer& texture); + // update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s void releaseResourceTexture(uint32_t slot); diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp index 7ef64343ea..03b53bc5cb 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp @@ -1,4 +1,4 @@ -// +// // GLBackendPipeline.cpp // libraries/gpu/src/gpu // @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "GLBackend.h" +#include + #include "GLShared.h" #include "GLPipeline.h" #include "GLShader.h" @@ -247,8 +249,11 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { return; } - TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + const auto& resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + bindResourceTexture(slot, resourceTexture); +} +void GLBackend::bindResourceTexture(uint32_t slot, const TexturePointer& resourceTexture) { if (!resourceTexture) { releaseResourceTexture(slot); return; @@ -269,11 +274,11 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { glActiveTexture(GL_TEXTURE0 + slot); glBindTexture(target, to); - (void) CHECK_GL_ERROR(); + (void)CHECK_GL_ERROR(); _resource._textures[slot] = resourceTexture; - _stats._RSAmountTextureMemoryBounded += (int) object->size(); + _stats._RSAmountTextureMemoryBounded += (int)object->size(); } else { releaseResourceTexture(slot); @@ -281,6 +286,19 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) { } } +void GLBackend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { + const auto& textureTablePointer = batch._textureTables.get(batch._params[paramOffset]._uint); + if (!textureTablePointer) { + return; + } + + const auto& textureTable = *textureTablePointer; + const auto& textures = textureTable.getTextures(); + for (GLuint slot = 0; slot < textures.size(); ++slot) { + bindResourceTexture(slot, textures[slot]); + } +} + int GLBackend::ResourceStageState::findEmptyTextureSlot() const { // start from the end of the slots, try to find an empty one that can be used for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) { @@ -290,4 +308,3 @@ int GLBackend::ResourceStageState::findEmptyTextureSlot() const { } return -1; } - diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp index 557591ffb6..e7a64c797e 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp @@ -55,7 +55,6 @@ static const std::string textureTableVersion { "#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n" }; - // Versions specific of the shader static const std::array VERSION_DEFINES { { "", @@ -70,15 +69,13 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co Shader::CompilationLogs compilationLogs(GLShader::NumVersions); shader.incrementCompilationAttempt(); - bool supportTextureTableBindless = true; - for (int version = 0; version < GLShader::NumVersions; version++) { auto& shaderObject = shaderObjects[version]; std::string shaderDefines = getBackendShaderHeader() + "\n" - + (supportTextureTableBindless ? textureTableVersion : "\n") - + DOMAIN_DEFINES[shader.getType()] + "\n" - + VERSION_DEFINES[version]; + + (supportsBindless() ? textureTableVersion : "\n") + + DOMAIN_DEFINES[shader.getType()] + "\n" + + VERSION_DEFINES[version]; if (handler) { bool retest = true; std::string currentSrc = shaderSource; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp index 7a26642024..010a7c479c 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.cpp @@ -73,9 +73,7 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin Shader::SlotSet uniforms; Shader::SlotSet textures; - Shader::SlotSet textureTables; Shader::SlotSet samplers; - //backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers); backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers); Shader::SlotSet resourceBuffers; diff --git a/libraries/gpu-gl/src/gpu/gl/GLShader.h b/libraries/gpu-gl/src/gpu/gl/GLShader.h index b2a1f189a2..3259982e93 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl/src/gpu/gl/GLShader.h @@ -17,8 +17,6 @@ struct ShaderObject { GLuint glprogram { 0 }; GLint transformCameraSlot { -1 }; GLint transformObjectSlot { -1 }; - GLint resourceTextureTableSlot0 { -1 }; - GLint resourceTextureTableSlot1 { -1 }; }; class GLShader : public GPUObject { diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 1b7882518d..42926fdb1c 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -157,9 +157,6 @@ protected: void resetInputStage() override; void updateInput() override; - // Resource stage - void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; - // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 28e474b729..381faf14fc 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -606,7 +606,3 @@ GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr& backend GL41ResourceTexture::~GL41ResourceTexture() { } - -void GL41Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { - -} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index e4a96349a9..2271dc6e01 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -19,7 +19,6 @@ #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 -#define GPU_BINDLESS_TEXTURES 1 namespace gpu { namespace gl45 { @@ -32,6 +31,9 @@ class GL45Backend : public GLBackend { friend class Context; public: +#if GPU_BINDLESS_TEXTURES + virtual bool supportsBindless() const override { return true; } +#endif #ifdef GPU_SSBO_TRANSFORM_OBJECT static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot @@ -60,15 +62,11 @@ public: Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void syncSampler() const override; - bool isBindless() const { #if GPU_BINDLESS_TEXTURES + bool isBindless() const { return _bindless.operator bool(); -#else - return false; -#endif } -#if GPU_BINDLESS_TEXTURES struct Bindless { uint64_t handle{ 0 }; uint32_t minMip{ 0 }; @@ -90,10 +88,9 @@ public: virtual const Bindless& getBindless() const; void releaseBindless() const; void recreateBindless() const; - virtual uint16 getMinMip() const = 0; - - private: + mutable Bindless _bindless; +#endif class InvalidSampler : public Sampler { public: InvalidSampler() { @@ -108,10 +105,6 @@ public: static const Sampler INVALID_SAMPLER; // This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w mutable Sampler _cachedSampler{ INVALID_SAMPLER }; - - mutable Bindless _bindless; - -#endif }; #if GPU_BINDLESS_TEXTURES @@ -147,7 +140,6 @@ public: protected: Size size() const override { return _size; } - uint16 getMinMip() const override { return 0; } void allocateStorage() const; void syncSampler() const override; @@ -179,18 +171,18 @@ public: friend class GL45Backend; using PromoteLambda = std::function; - const uvec4& getHandle(); protected: GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45VariableAllocationTexture(); Size size() const override { return _size; } - uint16 getMinMip() const override { return _populatedMip - _allocatedMip; } - virtual const Bindless& getBindless() const override; Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override; void copyTextureMipsInGPUMem(GLuint srcId, GLuint destId, uint16_t srcMipOffset, uint16_t destMipOffset, uint16_t populatedMips) override; +#if GPU_BINDLESS_TEXTURES + virtual const Bindless& getBindless() const override; +#endif }; class GL45ResourceTexture : public GL45VariableAllocationTexture { @@ -259,7 +251,6 @@ protected: GLuint getQueryID(const QueryPointer& query) override; GLQuery* syncGPUObject(const Query& query) override; - GL45TextureTable* syncGPUObject(const TextureTablePointer& textureTable); // Draw Stage void do_draw(const Batch& batch, size_t paramOffset) override; @@ -273,9 +264,6 @@ protected: void resetInputStage() override; void updateInput() override; - // Resource stage - void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; - // Synchronize the state cache of this Backend with the actual real state of the GL Context void transferTransformState(const Batch& batch) const override; void initTransform() override; @@ -295,6 +283,12 @@ protected: // Texture Management Stage void initTextureManagementStage() override; + +#if GPU_BINDLESS_TEXTURES + GL45TextureTable* syncGPUObject(const TextureTablePointer& textureTable); + // Resource stage + void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override; +#endif }; } } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index a87999781a..2a35415cc3 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -29,9 +29,6 @@ using namespace gpu::gl; using namespace gpu::gl45; #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 - -#pragma optimize("", off) - #define FORCE_STRICT_TEXTURE 0 #define ENABLE_SPARSE_TEXTURE 0 @@ -243,6 +240,7 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const return amountCopied; } +#if GPU_BINDLESS_TEXTURES void GL45Texture::releaseBindless() const { // Release the old handler SAMPLER_CACHE.releaseGLSampler(_bindless.sampler); @@ -267,9 +265,10 @@ const GL45Texture::Bindless& GL45Texture::getBindless() const { if (!_bindless) { recreateBindless(); } - _bindless.minMip = getMinMip(); return _bindless; } +#endif + void GL45Texture::syncSampler() const { const Sampler& sampler = _gpuObject.getSampler(); @@ -279,31 +278,33 @@ void GL45Texture::syncSampler() const { _cachedSampler = sampler; +#if GPU_BINDLESS_TEXTURES if (isBindless()) { recreateBindless(); + return; + } +#endif + + const auto& fm = FILTER_MODES[sampler.getFilter()]; + glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + if (sampler.doComparison()) { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); } else { - const auto& fm = FILTER_MODES[sampler.getFilter()]; - glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); - glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); - - if (sampler.doComparison()) { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB); - glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]); - } else { - glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); - glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); - - glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); - glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); - - glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); - glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); } - (void)CHECK_GL_ERROR(); + + glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + + glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); + glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + + glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip()); + glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); } // Fixed allocation textures, used for strict resources & framebuffer attachments @@ -378,6 +379,7 @@ GL45StrictResourceTexture::~GL45StrictResourceTexture() { } // Encapsulate bindless textures +#if GPU_BINDLESS_TEXTURES using GL45TextureTable = GL45Backend::GL45TextureTable; GLuint GL45TextureTable::allocate() { @@ -416,10 +418,14 @@ GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureT const auto& textureTable = *textureTablePointer; // Find the target handles + auto defaultTextures = gpu::TextureTable::getDefault()->getTextures(); auto textures = textureTable.getTextures(); GL45TextureTable::BindlessArray handles{}; for (size_t i = 0; i < textures.size(); ++i) { auto texture = textures[i]; + if (!texture) { + texture = defaultTextures[i]; + } if (!texture) { continue; } @@ -444,10 +450,15 @@ GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureT } void GL45Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) { - auto textureTable = batch._textureTables.get(batch._params[paramOffset]._uint); + auto textureTablePointer = batch._textureTables.get(batch._params[paramOffset]._uint); + if (!textureTablePointer) { + return; + } + auto slot = batch._params[paramOffset + 1]._uint; - GL45TextureTable* glTextureTable = syncGPUObject(textureTable); + GL45TextureTable* glTextureTable = syncGPUObject(textureTablePointer); if (glTextureTable) { glBindBufferBase(GL_UNIFORM_BUFFER, slot + GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET, glTextureTable->_id); } } +#endif diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 293b34fb39..aaeb786c51 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -41,11 +41,16 @@ GL45VariableAllocationTexture::~GL45VariableAllocationTexture() { Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0); } +#if GPU_BINDLESS_TEXTURES const GL45Texture::Bindless& GL45VariableAllocationTexture::getBindless() const { - auto& result = Parent::getBindless(); + // The parent call may re-initialize the _bindless member, so we need to call it first + const auto& result = Parent::getBindless(); + // Make sure the referenced structure has the correct minimum available mip value _bindless.minMip = _populatedMip - _allocatedMip; + // Now return the result return result; } +#endif Size GL45VariableAllocationTexture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const { Size amountCopied = 0; @@ -134,9 +139,13 @@ Size GL45ResourceTexture::copyMipsFromTexture() { void GL45ResourceTexture::syncSampler() const { Parent::syncSampler(); +#if GPU_BINDLESS_TEXTURES if (!isBindless()) { glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); } +#else + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); +#endif } void GL45ResourceTexture::promote() { @@ -146,10 +155,12 @@ void GL45ResourceTexture::promote() { uint16_t targetAllocatedMip = _allocatedMip - std::min(_allocatedMip, 2); targetAllocatedMip = std::max(_minAllocatedMip, targetAllocatedMip); +#if GPU_BINDLESS_TEXTURES bool bindless = isBindless(); if (bindless) { releaseBindless(); } +#endif GLuint oldId = _id; auto oldSize = _size; @@ -164,14 +175,17 @@ void GL45ResourceTexture::promote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); +#if GPU_BINDLESS_TEXTURES if (bindless) { getBindless(); } +#endif // destroy the old texture glDeleteTextures(1, &oldId); // Update sampler + _cachedSampler = InvalidSampler(); syncSampler(); // update the memory usage @@ -188,10 +202,12 @@ void GL45ResourceTexture::demote() { auto oldSize = _size; auto oldPopulatedMip = _populatedMip; +#if GPU_BINDLESS_TEXTURES bool bindless = isBindless(); if (bindless) { releaseBindless(); } +#endif // allocate new texture const_cast(_id) = allocate(_gpuObject); @@ -202,14 +218,17 @@ void GL45ResourceTexture::demote() { // copy pre-existing mips copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); +#if GPU_BINDLESS_TEXTURES if (bindless) { getBindless(); } +#endif // destroy the old texture glDeleteTextures(1, &oldId); // Update sampler + _cachedSampler = InvalidSampler(); syncSampler(); // update the memory usage diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 45d86757df..550175ef75 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -325,16 +325,16 @@ void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) { _params.emplace_back(slot); } +void Batch::setResourceTexture(uint32 slot, const TextureView& view) { + setResourceTexture(slot, view._texture); +} + void Batch::setResourceTextureTable(const TextureTablePointer& textureTable, uint32 slot) { ADD_COMMAND(setResourceTextureTable); _params.emplace_back(_textureTables.cache(textureTable)); _params.emplace_back(slot); } -void Batch::setResourceTexture(uint32 slot, const TextureView& view) { - setResourceTexture(slot, view._texture); -} - void Batch::setFramebuffer(const FramebufferPointer& framebuffer) { ADD_COMMAND(setFramebuffer); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 8eb769a6fe..2db1b9b420 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -30,11 +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, }; @@ -409,9 +404,10 @@ public: return offset; } - Data get(uint32 offset) const { + const Data& get(uint32 offset) const { if (offset >= _items.size()) { - return Data(); + static const Data EMPTY; + return EMPTY; } return (_items.data() + offset)->_data; } diff --git a/libraries/gpu/src/gpu/TextureTable.cpp b/libraries/gpu/src/gpu/TextureTable.cpp index 17a9e87f3e..40f3decc83 100644 --- a/libraries/gpu/src/gpu/TextureTable.cpp +++ b/libraries/gpu/src/gpu/TextureTable.cpp @@ -8,6 +8,7 @@ #include "TextureTable.h" #include "Texture.h" +#include using namespace gpu; TextureTable::TextureTable() { } @@ -42,7 +43,9 @@ void TextureTable::setTexture(size_t index, const TextureView& textureView) { TextureTable::Array TextureTable::getTextures() const { Array result; - Lock lock(_mutex); - result = _textures; + { + Lock lock(_mutex); + result = _textures; + } return result; } diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h index 4307e60adb..02b777bbd6 100644 --- a/libraries/gpu/src/gpu/TextureTable.h +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -30,6 +30,7 @@ public: Array getTextures() const; Stamp getStamp() const { return _stamp; } + private: mutable Mutex _mutex; Array _textures; diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index d31a0cbd31..4ebf0eb1db 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -24,8 +24,6 @@ class Transform; -#define USE_BINDLESS_TEXTURES 1 - namespace graphics { class TextureMap; @@ -363,10 +361,7 @@ public: void setModel(const std::string& model) { _model = model; } -#if USE_BINDLESS_TEXTURES const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } - void setTextureTable(const gpu::TextureTablePointer& textureTable) { _textureTable = textureTable; } -#endif protected: std::string _name { "" }; @@ -375,9 +370,7 @@ private: mutable MaterialKey _key; mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _texMapArrayBuffer; -#if USE_BINDLESS_TEXTURES - mutable gpu::TextureTablePointer _textureTable; -#endif + mutable gpu::TextureTablePointer _textureTable{ std::make_shared() }; TextureMaps _textureMaps; diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 6c335353fd..d9d2cb2e47 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -48,10 +48,10 @@ TexMapArray getTexMapArray() { <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@> - - <@include gpu/TextureTable.slh@> +#ifdef GPU_TEXTURE_TABLE_BINDLESS + TextureTable(0, matTex); - +#else <@if withAlbedo@> uniform sampler2D albedoMap; @@ -170,8 +169,8 @@ float fetchScatteringMap(vec2 uv) { return texture(scatteringMap, uv).r; // boolean scattering for now } <@endif@> -<@endif@> -!> + +#endif <@endfunc@> diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index e4d71b98ee..6dfc099284 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -14,8 +14,6 @@ #include #include -#include - #include "DeferredLightingEffect.h" #include "RenderPipelines.h" diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 8165e09754..ef4b0a5683 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -612,22 +612,8 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) { #include "RenderPipelines.h" #include -#if USE_BINDLESS_TEXTURES -gpu::TextureTablePointer makeTextureTable() { - auto textureCache = DependencyManager::get(); - auto textureTable = std::make_shared(); - textureTable->setTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::ROUGHNESS, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::NORMAL, textureCache->getBlueTexture()); - textureTable->setTexture(ShapePipeline::Slot::METALLIC, textureCache->getBlackTexture()); - textureTable->setTexture(ShapePipeline::Slot::OCCLUSION, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::SCATTERING, textureCache->getWhiteTexture()); - textureTable->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - return textureTable; -} -#endif - -void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) { +// FIXME find a better way to setup the default textures +void RenderPipelines::bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) { if (!material) { return; } @@ -645,63 +631,65 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc numUnlit++; } -#if USE_BINDLESS_TEXTURES - if (!material->getTextureTable()) { - material->setTextureTable(makeTextureTable()); - } - - batch.setResourceTextureTable(material->getTextureTable()); - if (!enableTextures) { - return; - } - const auto& drawMaterialTextures = material->getTextureTable(); // Albedo if (materialKey.isAlbedoMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); } } // Roughness map if (materialKey.isRoughnessMap()) { auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, textureCache->getWhiteTexture()); } } // Normal map if (materialKey.isNormalMap()) { auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, textureCache->getBlueTexture()); } } // Metallic map if (materialKey.isMetallicMap()) { auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, textureCache->getBlackTexture()); } } // Occlusion map if (materialKey.isOcclusionMap()) { auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, textureCache->getWhiteTexture()); } } // Scattering map if (materialKey.isScatteringMap()) { auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, itr->second->getTextureView()); + } else { + drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, textureCache->getWhiteTexture()); } } @@ -709,120 +697,19 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc if (materialKey.isLightmapMap()) { auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); } else { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); } } else if (materialKey.isEmissiveMap()) { auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { + if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); } else { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); } } - -#else - if (!enableTextures) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - return; - } - - // Albedo - if (materialKey.isAlbedoMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); - } - } - - // Roughness map - if (materialKey.isRoughnessMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); - } - } - - // Normal map - if (materialKey.isNormalMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); - } - } - - // Metallic map - if (materialKey.isMetallicMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); - } - } - - // Occlusion map - if (materialKey.isOcclusionMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); - } - } - - // Scattering map - if (materialKey.isScatteringMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); - - // texcoord are assumed to be the same has albedo - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); - } - } - - // Emissive / Lightmap - if (materialKey.isLightmapMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); - } - } else if (materialKey.isEmissiveMap()) { - auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); - - if (itr != textureMaps.end() && itr->second->isDefined()) { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); - } else { - batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); - } - } -#endif + batch.setResourceTextureTable(material->getTextureTable()); } diff --git a/libraries/render-utils/src/RenderPipelines.h b/libraries/render-utils/src/RenderPipelines.h index 9b9ad2c001..b7d22bc72d 100644 --- a/libraries/render-utils/src/RenderPipelines.h +++ b/libraries/render-utils/src/RenderPipelines.h @@ -15,7 +15,7 @@ class RenderPipelines { public: - static void bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures); + static void bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures); }; From 2598be16f81734e86e00f2789bc2111bcdf448b8 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Sat, 10 Mar 2018 21:46:20 -0800 Subject: [PATCH 11/45] Updating default mouse pitch/yaw input to be more stabilized --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b6fa3fde96..5b49fcd11c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -67,8 +67,8 @@ using namespace std; const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f; -const float YAW_SPEED_DEFAULT = 100.0f; // degrees/sec -const float PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec +const float YAW_SPEED_DEFAULT = 75.0f; // degrees/sec +const float PITCH_SPEED_DEFAULT = 50.0f; // degrees/sec const float MAX_BOOST_SPEED = 0.5f * DEFAULT_AVATAR_MAX_WALKING_SPEED; // action motor gets additive boost below this speed const float MIN_AVATAR_SPEED = 0.05f; From 748507f1e357b7a03177f847c63362297de9663e Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Sat, 10 Mar 2018 22:20:00 -0800 Subject: [PATCH 12/45] Increasing speed on mousescroll - zooming in/out of avatar --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5b49fcd11c..8bbbef041a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2229,7 +2229,7 @@ void MyAvatar::updateActionMotor(float deltaTime) { } float boomChange = getDriveKey(ZOOM); - _boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange; + _boomLength += 4.0f * _boomLength * boomChange + boomChange * boomChange; _boomLength = glm::clamp(_boomLength, ZOOM_MIN, ZOOM_MAX); } From c793a8d2c0bf7304a06e4e2b315e7fe03101f3a0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 12 Mar 2018 12:28:12 -0700 Subject: [PATCH 13/45] Move bindless compile time flag to GL45 backend, fix warnings and compile errors --- libraries/gpu-gl-common/src/gpu/gl/GLBackend.h | 2 -- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 14 +++----------- .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 13 ++++++++++++- .../src/gpu/gl45/GL45BackendVariableTexture.cpp | 4 ++-- libraries/gpu/src/gpu/TextureTable.cpp | 5 ++++- libraries/gpu/src/gpu/TextureTable.h | 10 ++++++---- 6 files changed, 27 insertions(+), 21 deletions(-) diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 0d85ca6789..feff3e2710 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -55,8 +55,6 @@ #define GPU_STEREO_CAMERA_BUFFER #endif -#define GPU_BINDLESS_TEXTURES 0 - namespace gpu { namespace gl { class GLBackend : public Backend, public std::enable_shared_from_this { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 22b5ad87e0..c23a83eaf9 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -20,6 +20,7 @@ #define INCREMENTAL_TRANSFER 0 #define GPU_SSBO_TRANSFORM_OBJECT 1 +#define GPU_BINDLESS_TEXTURES 0 namespace gpu { namespace gl45 { @@ -92,20 +93,11 @@ public: private: mutable Bindless _bindless; #endif - class InvalidSampler : public Sampler { - public: - InvalidSampler() { - _desc._borderColor = vec4(-1.0f); - } - operator const Sampler&() const { - return *this; - } - }; + static Sampler getInvalidSampler(); - static const Sampler INVALID_SAMPLER; // This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w - mutable Sampler _cachedSampler{ INVALID_SAMPLER }; + mutable Sampler _cachedSampler{ getInvalidSampler() }; }; #if GPU_BINDLESS_TEXTURES diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 3791a9802b..5a5d701150 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -163,7 +163,18 @@ private: }; static GLSamplerCache SAMPLER_CACHE; -const Sampler GL45Texture::INVALID_SAMPLER = GL45Texture::InvalidSampler(); + + +Sampler GL45Texture::getInvalidSampler() { + static Sampler INVALID_SAMPLER; + static std::once_flag once; + std::call_once(once, [] { + Sampler::Desc invalidDesc; + invalidDesc._borderColor = vec4(-1.0f); + INVALID_SAMPLER = Sampler(invalidDesc); + }); + return INVALID_SAMPLER; +} GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture) : GLTexture(backend, texture, allocate(texture)) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 150ea7a488..08d077605d 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -185,7 +185,7 @@ void GL45ResourceTexture::promote() { glDeleteTextures(1, &oldId); // Update sampler - _cachedSampler = InvalidSampler(); + _cachedSampler = getInvalidSampler(); syncSampler(); // update the memory usage @@ -228,7 +228,7 @@ void GL45ResourceTexture::demote() { glDeleteTextures(1, &oldId); // Update sampler - _cachedSampler = InvalidSampler(); + _cachedSampler = getInvalidSampler(); syncSampler(); // update the memory usage diff --git a/libraries/gpu/src/gpu/TextureTable.cpp b/libraries/gpu/src/gpu/TextureTable.cpp index 40f3decc83..0c3a43808b 100644 --- a/libraries/gpu/src/gpu/TextureTable.cpp +++ b/libraries/gpu/src/gpu/TextureTable.cpp @@ -11,6 +11,9 @@ #include using namespace gpu; + +const size_t TextureTable::COUNT{ TEXTURE_TABLE_COUNT }; + TextureTable::TextureTable() { } TextureTable::TextureTable(const std::initializer_list& textures) { @@ -23,7 +26,7 @@ TextureTable::TextureTable(const std::initializer_list& textures } } -TextureTable::TextureTable(const std::array& textures) : _stamp(1), _textures(textures) { +TextureTable::TextureTable(const Array& textures) : _textures(textures) { } void TextureTable::setTexture(size_t index, const TexturePointer& texturePointer) { diff --git a/libraries/gpu/src/gpu/TextureTable.h b/libraries/gpu/src/gpu/TextureTable.h index 02b777bbd6..794b8535d0 100644 --- a/libraries/gpu/src/gpu/TextureTable.h +++ b/libraries/gpu/src/gpu/TextureTable.h @@ -12,15 +12,17 @@ #include +#define TEXTURE_TABLE_COUNT 8 + namespace gpu { class TextureTable { public: - static const size_t COUNT = 8; - using Array = std::array; + static const size_t COUNT; + using Array = std::array; TextureTable(); TextureTable(const std::initializer_list& textures); - TextureTable(const std::array& textures); + TextureTable(const Array& textures); // Only for gpu::Context const GPUObjectPointer gpuObject{}; @@ -34,7 +36,7 @@ public: private: mutable Mutex _mutex; Array _textures; - Stamp _stamp{ 0 }; + Stamp _stamp{ 1 }; }; } From c385bf26e937adf235dbaee02031a4ade481b438 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 15 Mar 2018 19:43:00 +0100 Subject: [PATCH 14/45] Do not use timer for switching bubble button active state --- scripts/system/bubble.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js index 994bde49eb..f1a403a49c 100644 --- a/scripts/system/bubble.js +++ b/scripts/system/bubble.js @@ -89,14 +89,8 @@ bubbleOverlayTimestamp = nowTimestamp; Script.update.connect(update); updateConnected = true; - - // Flash button - if (!bubbleFlashTimer) { - bubbleFlashTimer = Script.setInterval(function () { - writeButtonProperties(bubbleButtonFlashState); - bubbleButtonFlashState = !bubbleButtonFlashState; - }, 500); - } + writeButtonProperties(bubbleButtonFlashState); + bubbleButtonFlashState = !bubbleButtonFlashState; } // Called from the C++ scripting interface to show the bubble overlay From 0d6e8f349096b2b4265a9806413a2791f0f23388 Mon Sep 17 00:00:00 2001 From: Alexia Mandeville Date: Fri, 16 Mar 2018 11:39:02 -0700 Subject: [PATCH 15/45] Revert "Update repo script with marketplace script" This reverts commit 5139f3f50328c0299801906ba435d5e1528c72f8. --- scripts/tutorials/entity_scripts/sit.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 9de65d7037..70456ea493 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -12,9 +12,9 @@ Script.include("/~/system/libraries/utils.js"); if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position){ - position = position || 0; - return this.substr(position, searchString.length) === searchString; - }; + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; } var SETTING_KEY = "com.highfidelity.avatar.isSitting"; @@ -122,10 +122,20 @@ this.rolesToOverride = function() { return MyAvatar.getAnimationRoles().filter(function(role) { - return !(role.startsWith("right") || role.startsWith("left")); + return !(role.startsWith("right") || role.startsWith("left")); }); } + // Handler for user changing the avatar model while sitting. There's currently an issue with changing avatar models while override role animations are applied, + // so to avoid that problem, re-apply the role overrides once the model has finished changing. + this.modelURLChangeFinished = function () { + print("Sitter's model has FINISHED changing. Reapply anim role overrides."); + var roles = this.rolesToOverride(); + for (i in roles) { + MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); + } + } + this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); @@ -164,12 +174,14 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); + MyAvatar.onLoadComplete.connect(this, this.modelURLChangeFinished); } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); + MyAvatar.onLoadComplete.disconnect(this, this.modelURLChangeFinished); if (MyAvatar.sessionUUID === this.getSeatUser()) { this.setSeatUser(null); @@ -331,7 +343,7 @@ } this.cleanupOverlay(); } - + this.clickDownOnEntity = function (id, event) { if (isInEditMode()) { return; @@ -340,4 +352,4 @@ this.sitDown(); } } -}); \ No newline at end of file +}); From 69f462baeb79dc6d1c3dc36dfad84c68ff1adfdc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 19 Mar 2018 18:53:00 -0700 Subject: [PATCH 16/45] Disable elbow pole vectors, solve from joint limit centers. --- libraries/animation/src/Rig.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 848f384687..7996c3372c 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1246,6 +1246,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo, const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo) { + const bool ENABLE_POLE_VECTORS = false; const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f; int hipsIndex = indexOfJoint("Hips"); @@ -1268,7 +1269,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand"); int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm"); int elbowJointIndex = _animSkeleton->nameToJointIndex("LeftForeArm"); - if (!leftArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { + if (ENABLE_POLE_VECTORS && !leftArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, true); // smooth toward desired pole vector from previous pole vector... to reduce jitter @@ -1315,7 +1316,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab int handJointIndex = _animSkeleton->nameToJointIndex("RightHand"); int armJointIndex = _animSkeleton->nameToJointIndex("RightArm"); int elbowJointIndex = _animSkeleton->nameToJointIndex("RightForeArm"); - if (!rightArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { + if (ENABLE_POLE_VECTORS && !rightArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, false); // smooth toward desired pole vector from previous pole vector... to reduce jitter @@ -1555,18 +1556,16 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo updateFeet(leftFootEnabled, rightFootEnabled, params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot]); + + // Always relax IK chains toward joint limit centers. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); + // if the hips or the feet are being controlled. if (hipsEnabled || rightFootEnabled || leftFootEnabled) { - // for more predictable IK solve from the center of the joint limits, not from the underpose - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); - // replace the feet animation with the default pose, this is to prevent unexpected toe wiggling. _animVars.set("defaultPoseOverlayAlpha", 1.0f); _animVars.set("defaultPoseOverlayBoneSet", (int)AnimOverlay::BothFeetBoneSet); } else { - // augment the IK with the underPose. - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses); - // feet should follow source animation _animVars.unset("defaultPoseOverlayAlpha"); _animVars.unset("defaultPoseOverlayBoneSet"); From faf8328d6aeef60da16ee1b09a9d89b873adfbba Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 20 Mar 2018 15:47:30 +0100 Subject: [PATCH 17/45] Fix invalid message if cancel adding asset to AssetServer --- interface/src/scripting/AssetMappingsScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index 4bc8ec0bd3..4a6b0e9548 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -80,7 +80,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", dropEvent ? dropHelpText : helpText, mapping); - if (!result.isValid()) { + if (!result.isValid() || result.toString() == "") { completedCallback.call({ -1 }); return; } From f19b1d9890fb360dd7949c05054439561e9bab19 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 20 Mar 2018 18:12:55 -0700 Subject: [PATCH 18/45] Fix for character walk animations in desktop mode. --- libraries/animation/src/Rig.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 7996c3372c..0833b28142 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1557,8 +1557,13 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot]); - // Always relax IK chains toward joint limit centers. - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); + if (headEnabled) { + // Blend IK chains toward the joint limit centers, this should stablize head and hand ik. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); + } else { + // Blend IK chains toward the UnderPoses, so some of the animaton motion is present in the IK solution. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses); + } // if the hips or the feet are being controlled. if (hipsEnabled || rightFootEnabled || leftFootEnabled) { From f62e1ed54e9e2d30654b7fa0032a0e7e0a3e7b9c Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Thu, 22 Mar 2018 15:29:41 -0700 Subject: [PATCH 19/45] disable add button on model until text is entered --- .../resources/qml/hifi/tablet/NewModelDialog.qml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 3debc8b9e7..4586daf2a7 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -71,6 +71,10 @@ Rectangle { onAccepted: { newModelDialog.keyboardEnabled = false; } + + onTextChanged : { + button1.enabled = true; + } MouseArea { anchors.fill: parent @@ -118,13 +122,6 @@ Rectangle { height: 400 spacing: 20 - Image { - id: image1 - width: 30 - height: 30 - source: "qrc:/qtquickplugin/images/template_image.png" - } - Text { id: text2 width: 160 @@ -200,6 +197,7 @@ Rectangle { id: button1 text: qsTr("Add") z: -1 + enabled: false onClicked: { newModelDialog.sendToScript({ method: "newModelDialogAdd", From 0647155c30317406637ca372ca0670f6592d3cbe Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Thu, 22 Mar 2018 15:33:23 -0700 Subject: [PATCH 20/45] re-add experimental image removal --- interface/resources/qml/hifi/tablet/NewModelDialog.qml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 4586daf2a7..9994d9708d 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -122,6 +122,13 @@ Rectangle { height: 400 spacing: 20 + Image { + id: image1 + width: 30 + height: 30 + source: "qrc:/qtquickplugin/images/template_image.png" + } + Text { id: text2 width: 160 From 12445596181d0bcdc6e89da1bb081c7fda50f23b Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Thu, 22 Mar 2018 15:37:12 -0700 Subject: [PATCH 21/45] remove spaces for clean-ness --- interface/resources/qml/hifi/tablet/NewModelDialog.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 9994d9708d..ec8289d68e 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -122,11 +122,11 @@ Rectangle { height: 400 spacing: 20 - Image { - id: image1 - width: 30 - height: 30 - source: "qrc:/qtquickplugin/images/template_image.png" + Image { + id: image1 + width: 30 + height: 30 + source: "qrc:/qtquickplugin/images/template_image.png" } Text { From f6bbdec90277bb06c0b48182d4b1d51b60810fb7 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 23 Mar 2018 20:20:40 +0300 Subject: [PATCH 22/45] remove 'isHMD' from input parameters of AudioDeviceList::onDevicesChanged note: having 'isHMD' as a parameter doesn't make sense because function rebuilds model which is used by both HMD and Desktop --- interface/src/scripting/AudioDevices.cpp | 42 +++++++++++++----------- interface/src/scripting/AudioDevices.h | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index a130b46877..1b6b71a947 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -200,28 +200,34 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); } -void AudioDeviceList::onDevicesChanged(const QList& devices, bool isHMD) { - QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; - - const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; +void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); _devices.clear(); foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; - bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; device.info = deviceInfo; device.display = device.info.deviceName() .replace("High Definition", "HD") .remove("Device") .replace(" )", ")"); - if (!selectedDevice.isNull()) { - isSelected = (device.info == selectedDevice); - } else { - //no selected device for context. fallback to saved - isSelected = (device.info.deviceName() == savedDeviceName); + + for (bool isHMD : {false, true}) + { + QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; + + if (!selectedDevice.isNull()) { + isSelected = (device.info == selectedDevice); + } + else { + //no selected device for context. fallback to saved + const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; + isSelected = (device.info.deviceName() == savedDeviceName); + } } + qDebug() << "adding audio device:" << device.display << device.selectedDesktop << device.selectedHMD << _mode; _devices.push_back(newDevice(device)); } @@ -271,12 +277,10 @@ AudioDevices::AudioDevices(bool& contextIsHMD) : _contextIsHMD(contextIsHMD) { // connections are made after client is initialized, so we must also fetch the devices const QList& devicesInput = client->getAudioDevices(QAudio::AudioInput); const QList& devicesOutput = client->getAudioDevices(QAudio::AudioOutput); - //setup HMD devices - _inputs.onDevicesChanged(devicesInput, true); - _outputs.onDevicesChanged(devicesOutput, true); - //setup Desktop devices - _inputs.onDevicesChanged(devicesInput, false); - _outputs.onDevicesChanged(devicesOutput, false); + + //setup devices + _inputs.onDevicesChanged(devicesInput); + _outputs.onDevicesChanged(devicesOutput); } AudioDevices::~AudioDevices() {} @@ -375,11 +379,9 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList& devices, bool isHMD); + void onDevicesChanged(const QList& devices); protected: friend class AudioDevices; From 3c45f17d709a1ffd04a958e2d55992cb1cb84645 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Sun, 25 Mar 2018 12:52:55 +0300 Subject: [PATCH 23/45] remove unused code --- interface/src/scripting/AudioDevices.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index 1b6b71a947..dbdbe778b2 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -182,7 +182,6 @@ void AudioDeviceList::resetDevice(bool contextIsHMD) { } void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD) { - auto oldDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; selectedDevice = device; From 8e551f4dc0fd9d93765fe54742273cce973b55f6 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Sun, 25 Mar 2018 13:49:59 +0300 Subject: [PATCH 24/45] re-select re-plugged device --- interface/src/scripting/AudioDevices.cpp | 31 +++++++++++++++++++++--- interface/src/scripting/AudioDevices.h | 7 +++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index dbdbe778b2..327f9dab9f 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -202,8 +202,7 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); - _devices.clear(); - + QList> newDevices; foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; device.info = deviceInfo; @@ -225,12 +224,28 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { const QString& savedDeviceName = isHMD ? _hmdSavedDeviceName : _desktopSavedDeviceName; isSelected = (device.info.deviceName() == savedDeviceName); } + + if (isSelected) { + // check if this device *is not* in old devices list - it means it was just re-plugged so needs to be selected explicitly + bool isNewDevice = true; + for (auto& oldDevice : _devices) { + if (oldDevice->info.deviceName() == device.info.deviceName()) { + isNewDevice = false; + break; + } + } + + if (isNewDevice) { + emit selectedDevicePlugged(device.info, isHMD); + } + } } qDebug() << "adding audio device:" << device.display << device.selectedDesktop << device.selectedHMD << _mode; - _devices.push_back(newDevice(device)); + newDevices.push_back(newDevice(device)); } + _devices.swap(newDevices); endResetModel(); } @@ -379,8 +394,18 @@ void AudioDevices::onDevicesChanged(QAudio::Mode mode, const QList Date: Mon, 26 Mar 2018 01:05:05 +0300 Subject: [PATCH 25/45] temporarily select 'similar-by-title' device if previously selected one was unlplugged; re-select originally selected device if it was re-plugged --- interface/src/scripting/AudioDevices.cpp | 89 +++++++++++++++++++++++- interface/src/scripting/AudioDevices.h | 2 + 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/interface/src/scripting/AudioDevices.cpp b/interface/src/scripting/AudioDevices.cpp index 327f9dab9f..34a3630b78 100644 --- a/interface/src/scripting/AudioDevices.cpp +++ b/interface/src/scripting/AudioDevices.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include @@ -199,10 +200,74 @@ void AudioDeviceList::onDeviceChanged(const QAudioDeviceInfo& device, bool isHMD emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, 0)); } +// Function returns 'strings similarity' as a number. The lesser number - the more similar strings are. Absolutely equal strings should return 0. +// Optimized version kindly provided by Ken +int levenshteinDistance(const QString& s1, const QString& s2) { + const int m = s1.size(); + const int n = s2.size(); + + if (m == 0) { + return n; + } + if (n == 0) { + return m; + } + + auto cost = (int*)alloca((n + 1) * sizeof(int)); + + for (int j = 0; j <= n; j++) { + cost[j] = j; + } + + for (int i = 0; i < m; i++) { + + int prev = i; + cost[0] = i + 1; + + for (int j = 0; j < n; j++) { + + int temp = cost[j + 1]; + cost[j + 1] = (s1[i] == s2[j]) ? prev : std::min(cost[j], std::min(temp, prev)) + 1; + prev = temp; + } + } + return cost[n]; +} + +std::shared_ptr getSimilarDevice(const QString& deviceName, const QList>& devices) { + + int minDistance = INT_MAX; + int minDistanceIndex = 0; + + for (auto i = 0; i < devices.length(); ++i) { + auto distance = levenshteinDistance(deviceName, devices[i]->info.deviceName()); + if (distance < minDistance) { + minDistance = distance; + minDistanceIndex = i; + } + } + + return devices[minDistanceIndex]; +} + void AudioDeviceList::onDevicesChanged(const QList& devices) { beginResetModel(); QList> newDevices; + bool hmdIsSelected = false; + bool desktopIsSelected = false; + + foreach(const QAudioDeviceInfo& deviceInfo, devices) { + for (bool isHMD : {false, true}) { + auto &backupSelectedDeviceName = isHMD ? _backupSelectedHMDDeviceName : _backupSelectedDesktopDeviceName; + if (deviceInfo.deviceName() == backupSelectedDeviceName) { + QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; + selectedDevice = deviceInfo; + backupSelectedDeviceName.clear(); + } + } + } + foreach(const QAudioDeviceInfo& deviceInfo, devices) { AudioDevice device; device.info = deviceInfo; @@ -211,8 +276,7 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { .remove("Device") .replace(" )", ")"); - for (bool isHMD : {false, true}) - { + for (bool isHMD : {false, true}) { QAudioDeviceInfo& selectedDevice = isHMD ? _selectedHMDDevice : _selectedDesktopDevice; bool &isSelected = isHMD ? device.selectedHMD : device.selectedDesktop; @@ -226,6 +290,12 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { } if (isSelected) { + if (isHMD) { + hmdIsSelected = isSelected; + } else { + desktopIsSelected = isSelected; + } + // check if this device *is not* in old devices list - it means it was just re-plugged so needs to be selected explicitly bool isNewDevice = true; for (auto& oldDevice : _devices) { @@ -245,6 +315,21 @@ void AudioDeviceList::onDevicesChanged(const QList& devices) { newDevices.push_back(newDevice(device)); } + if (!newDevices.isEmpty()) { + if (!hmdIsSelected) { + _backupSelectedHMDDeviceName = !_selectedHMDDevice.isNull() ? _selectedHMDDevice.deviceName() : _hmdSavedDeviceName; + auto device = getSimilarDevice(_backupSelectedHMDDeviceName, newDevices); + device->selectedHMD = true; + emit selectedDevicePlugged(device->info, true); + } + if (!desktopIsSelected) { + _backupSelectedDesktopDeviceName = !_selectedDesktopDevice.isNull() ? _selectedDesktopDevice.deviceName() : _desktopSavedDeviceName; + auto device = getSimilarDevice(_backupSelectedDesktopDeviceName, newDevices); + device->selectedDesktop = true; + emit selectedDevicePlugged(device->info, false); + } + } + _devices.swap(newDevices); endResetModel(); } diff --git a/interface/src/scripting/AudioDevices.h b/interface/src/scripting/AudioDevices.h index 72d5fccedb..3d12f93113 100644 --- a/interface/src/scripting/AudioDevices.h +++ b/interface/src/scripting/AudioDevices.h @@ -65,6 +65,8 @@ protected: const QAudio::Mode _mode; QAudioDeviceInfo _selectedDesktopDevice; QAudioDeviceInfo _selectedHMDDevice; + QString _backupSelectedDesktopDeviceName; + QString _backupSelectedHMDDeviceName; QList> _devices; QString _hmdSavedDeviceName; QString _desktopSavedDeviceName; From bf48ecda6d199b6b4c3f4c1c2a88203aa27b672d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 26 Mar 2018 14:40:31 -0700 Subject: [PATCH 26/45] Fix cert location for content sets --- assignment-client/src/entities/EntityServer.cpp | 12 ++++++++---- .../qml/hifi/commerce/checkout/Checkout.qml | 2 +- .../qml/hifi/commerce/purchases/PurchasedItem.qml | 2 +- .../qml/hifi/commerce/purchases/Purchases.qml | 2 +- interface/src/commerce/Ledger.cpp | 5 ++++- interface/src/commerce/Ledger.h | 2 +- interface/src/commerce/QmlCommerce.cpp | 4 +++- interface/src/commerce/QmlCommerce.h | 2 +- 8 files changed, 20 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index e394884dc2..a6c35390cc 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -470,7 +470,6 @@ void EntityServer::startDynamicDomainVerification() { // Delete the entity if it doesn't pass static certificate verification tree->deleteEntity(i.value(), true); } else { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest; networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); @@ -490,9 +489,14 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() - << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); - tree->deleteEntity(i.value(), true); + if (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated()/1000 > _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS) { + qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() + << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); + qCDebug(entities) << "Time since rez (seconds):" << (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated() / 1000) / 1000; + tree->deleteEntity(i.value(), true); + } else { + qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << i.value(); + } } else { qCDebug(entities) << "Entity passed dynamic domain verification:" << i.value(); } diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 9933953fe8..85469c7f94 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -772,7 +772,7 @@ Rectangle { lightboxPopup.button1text = "CANCEL"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemHref + "');" + + lightboxPopup.button2method = "Commerce.replaceContentSet('" + root.itemHref + "', '" + root.certificateId + "');" + "root.visible = false;rezzedNotifContainer.visible = true; rezzedNotifContainerTimer.start();" + "UserActivityLogger.commerceEntityRezzed('" + root.itemId + "', 'checkout', '" + root.itemType + "');"; lightboxPopup.visible = true; diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 4cfa61c9ed..2aac269d56 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -564,7 +564,7 @@ Item { onClicked: { Tablet.playSound(TabletEnums.ButtonClick); if (root.itemType === "contentSet") { - sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref}); + sendToPurchases({method: 'showReplaceContentLightbox', itemHref: root.itemHref, certID: root.certificateId}); } else if (root.itemType === "avatar") { sendToPurchases({method: 'showChangeAvatarLightbox', itemName: root.itemName, itemHref: root.itemHref}); } else if (root.itemType === "app") { diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 726e6bd338..1e935875e6 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -486,7 +486,7 @@ Rectangle { lightboxPopup.button1text = "CANCEL"; lightboxPopup.button1method = "root.visible = false;" lightboxPopup.button2text = "CONFIRM"; - lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemHref + "'); root.visible = false;"; + lightboxPopup.button2method = "Commerce.replaceContentSet('" + msg.itemHref + "', '" + msg.certID + "'); root.visible = false;"; lightboxPopup.visible = true; } else if (msg.method === "showChangeAvatarLightbox") { lightboxPopup.titleText = "Change Avatar"; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 0a9e867323..cb06cdfed7 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -293,7 +293,7 @@ void Ledger::account() { // The api/failResponse is called just for the side effect of logging. void Ledger::updateLocationSuccess(QNetworkReply& reply) { apiResponse("updateLocation", reply); } void Ledger::updateLocationFailure(QNetworkReply& reply) { failResponse("updateLocation", reply); } -void Ledger::updateLocation(const QString& asset_id, const QString location, const bool controlledFailure) { +void Ledger::updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings, const bool controlledFailure) { auto wallet = DependencyManager::get(); auto walletScriptingInterface = DependencyManager::get(); uint walletStatus = walletScriptingInterface->getWalletStatus(); @@ -308,6 +308,9 @@ void Ledger::updateLocation(const QString& asset_id, const QString location, con QJsonObject transaction; transaction["certificate_id"] = asset_id; transaction["place_name"] = location; + if (alsoUpdateSiblings) { + transaction["also_update_siblings"] = true; + } QJsonDocument transactionDoc{ transaction }; auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); signedSend("transaction", transactionString, key, "location", "updateLocationSuccess", "updateLocationFailure", controlledFailure); diff --git a/interface/src/commerce/Ledger.h b/interface/src/commerce/Ledger.h index da97206bbc..1ccab9c2b1 100644 --- a/interface/src/commerce/Ledger.h +++ b/interface/src/commerce/Ledger.h @@ -31,7 +31,7 @@ public: void inventory(const QStringList& keys); void history(const QStringList& keys, const int& pageNumber); void account(); - void updateLocation(const QString& asset_id, const QString location, const bool controlledFailure = false); + void updateLocation(const QString& asset_id, const QString& location, const bool& alsoUpdateSiblings = false, const bool controlledFailure = false); void certificateInfo(const QString& certificateId); void transferHfcToNode(const QString& hfc_key, const QString& nodeID, const int& amount, const QString& optionalMessage); void transferHfcToUsername(const QString& hfc_key, const QString& username, const int& amount, const QString& optionalMessage); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 8e956249cc..7e91ffaa62 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -190,7 +190,9 @@ void QmlCommerce::transferHfcToUsername(const QString& username, const int& amou ledger->transferHfcToUsername(key, username, amount, optionalMessage); } -void QmlCommerce::replaceContentSet(const QString& itemHref) { +void QmlCommerce::replaceContentSet(const QString& itemHref, const QString& certificateID) { + auto ledger = DependencyManager::get(); + ledger->updateLocation(certificateID, DependencyManager::get()->getPlaceName(), true); qApp->replaceDomainContent(itemHref); QJsonObject messageProperties = { { "status", "SuccessfulRequestToReplaceContent" }, diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index a3a0ebfd32..f58726e1d7 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -84,7 +84,7 @@ protected: Q_INVOKABLE void transferHfcToNode(const QString& nodeID, const int& amount, const QString& optionalMessage); Q_INVOKABLE void transferHfcToUsername(const QString& username, const int& amount, const QString& optionalMessage); - Q_INVOKABLE void replaceContentSet(const QString& itemHref); + Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID); Q_INVOKABLE QString getInstalledApps(); Q_INVOKABLE bool installApp(const QString& appHref); From 00c70278c838c1d187948e75ecdc46b68a1e6fc4 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 26 Mar 2018 15:03:10 -0700 Subject: [PATCH 27/45] Add getCreatedAgo() --- assignment-client/src/entities/EntityServer.cpp | 3 +-- libraries/entities/src/EntityItem.h | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index a6c35390cc..1862287b6d 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -489,10 +489,9 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - if (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated()/1000 > _MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS) { + if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/1000)) { qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); - qCDebug(entities) << "Time since rez (seconds):" << (QDateTime::currentMSecsSinceEpoch() - entity->getProperties().getCreated() / 1000) / 1000; tree->deleteEntity(i.value(), true); } else { qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << i.value(); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 0303964e18..962babb558 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -222,6 +222,10 @@ public: quint64 getCreated() const; /// get the created-time in useconds for the entity void setCreated(quint64 value); /// set the created-time in useconds for the entity + float getCreatedAgo() const /// Elapsed seconds since this entity was created + { + return (float)(usecTimestampNow() - getCreated()) / (float)USECS_PER_SECOND; + } /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME; } From db2f3451bd30ba144c6bba6e94c64f7cc347e297 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 26 Mar 2018 16:20:29 -0700 Subject: [PATCH 28/45] Support .content.zip content sets --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 2 +- interface/resources/qml/hifi/commerce/purchases/Purchases.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 85469c7f94..35c95a9a5c 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -188,7 +188,7 @@ Rectangle { onItemHrefChanged: { if (root.itemHref.indexOf(".fst") > -1) { root.itemType = "avatar"; - } else if (root.itemHref.indexOf('.json.gz') > -1) { + } else if (root.itemHref.indexOf('.json.gz') > -1 || root.itemHref.indexOf('.content.zip') > -1) { root.itemType = "contentSet"; } else if (root.itemHref.indexOf('.app.json') > -1) { root.itemType = "app"; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 1e935875e6..cdcfa4a13e 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -792,7 +792,7 @@ Rectangle { currentItemType = "avatar"; } else if (currentCategories.indexOf("Wearables") > -1) { currentItemType = "wearable"; - } else if (currentRootFileUrl.endsWith('.json.gz')) { + } else if (currentRootFileUrl.endsWith('.json.gz') || currentRootFileUrl.endsWith('.content.zip')) { currentItemType = "contentSet"; } else if (currentRootFileUrl.endsWith('.app.json')) { currentItemType = "app"; From d1d58eceab9c8f97fa43cd0e7ee2ffe3e01846d7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 27 Mar 2018 13:04:50 +1300 Subject: [PATCH 29/45] Add Window.raise() as replacement for Window.raiseMainWindow() --- interface/src/scripting/WindowScriptingInterface.cpp | 6 +++++- interface/src/scripting/WindowScriptingInterface.h | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 78f55f0d6e..58ec744f4e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -78,13 +78,17 @@ void WindowScriptingInterface::setFocus() { }); } -void WindowScriptingInterface::raiseMainWindow() { +void WindowScriptingInterface::raise() { // It's forbidden to call raise() from another thread. qApp->postLambdaEvent([] { qApp->raise(); }); } +void WindowScriptingInterface::raiseMainWindow() { + raise(); +} + /// Display an alert box /// \param const QString& message message to display /// \return QScriptValue::UndefinedValue diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 997e425e53..e3b092d011 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -68,9 +68,16 @@ public slots: */ void setFocus(); + /**jsdoc + * Raise the Interface window if it is minimized. If raised, the window gains focus. + * @function Window.raise + */ + void raise(); + /**jsdoc * Raise the Interface window if it is minimized. If raised, the window gains focus. * @function Window.raiseMainWindow + * @deprecated Use {@link Window.raise|raise} instead. */ void raiseMainWindow(); From 3d7f7f0e620270b6dc5b14bac5ac176c02139ad7 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 27 Mar 2018 14:05:43 -0700 Subject: [PATCH 30/45] fix parent tree grabbing --- .../system/controllers/controllerModules/farActionGrabEntity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 09cea58cea..07450e54ba 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -475,7 +475,7 @@ Script.include("/~/system/libraries/Xform.js"); entityID = targetEntity.id; targetProps = targetEntity.props; - if (entityIsGrabbable(targetProps)) { + if (entityIsGrabbable(targetProps) || entityIsGrabbable(this.targetObject.entityProps)) { if (!entityIsDistanceGrabbable(targetProps)) { this.targetObject.makeDynamic(); } From eb20181b6086c487542ac56e1773da8ef0d19d91 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 27 Mar 2018 14:18:01 -0700 Subject: [PATCH 31/45] Shut down the overlay interface on exit --- interface/src/ui/overlays/Overlays.cpp | 34 +++++++++++++++++++++++++- interface/src/ui/overlays/Overlays.h | 1 + 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 35274e4fbe..ee2f62c6bb 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -54,6 +54,7 @@ Overlays::Overlays() { } void Overlays::cleanupAllOverlays() { + _shuttingDown = true; QMap overlaysHUD; QMap overlaysWorld; { @@ -147,6 +148,10 @@ void Overlays::enable() { // Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder // class on packet processing threads Overlay::Pointer Overlays::getOverlay(OverlayID id) const { + if (_shuttingDown) { + return nullptr; + } + QMutexLocker locker(&_mutex); if (_overlaysHUD.contains(id)) { return _overlaysHUD[id]; @@ -157,6 +162,10 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const { } OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) { + if (_shuttingDown) { + return UNKNOWN_OVERLAY_ID; + } + if (QThread::currentThread() != thread()) { OverlayID result; PROFILE_RANGE(script, __FUNCTION__); @@ -261,6 +270,10 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) } OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { + if (_shuttingDown) { + return UNKNOWN_OVERLAY_ID; + } + OverlayID thisID = OverlayID(QUuid::createUuid()); overlay->setOverlayID(thisID); overlay->setStackOrder(_stackOrder++); @@ -283,6 +296,10 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) { } OverlayID Overlays::cloneOverlay(OverlayID id) { + if (_shuttingDown) { + return UNKNOWN_OVERLAY_ID; + } + if (QThread::currentThread() != thread()) { OverlayID result; PROFILE_RANGE(script, __FUNCTION__); @@ -301,6 +318,10 @@ OverlayID Overlays::cloneOverlay(OverlayID id) { } bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { + if (_shuttingDown) { + return false; + } + auto thisOverlay = getOverlay(id); if (!thisOverlay) { return false; @@ -320,6 +341,10 @@ bool Overlays::editOverlay(OverlayID id, const QVariant& properties) { } bool Overlays::editOverlays(const QVariant& propertiesById) { + if (_shuttingDown) { + return false; + } + bool defer2DOverlays = QThread::currentThread() != thread(); QVariantMap deferrred; @@ -351,6 +376,10 @@ bool Overlays::editOverlays(const QVariant& propertiesById) { } void Overlays::deleteOverlay(OverlayID id) { + if (_shuttingDown) { + return; + } + if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "deleteOverlay", Q_ARG(OverlayID, id)); return; @@ -374,6 +403,9 @@ void Overlays::deleteOverlay(OverlayID id) { } QString Overlays::getOverlayType(OverlayID overlayId) { + if (_shuttingDown) { + return ""; + } if (QThread::currentThread() != thread()) { QString result; PROFILE_RANGE(script, __FUNCTION__); @@ -389,7 +421,7 @@ QString Overlays::getOverlayType(OverlayID overlayId) { } OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { - if (!_enabled) { + if (_shuttingDown || !_enabled) { return UNKNOWN_OVERLAY_ID; } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index c3d87642f1..8eccbfa4c5 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -680,6 +680,7 @@ private: unsigned int _stackOrder { 1 }; bool _enabled = true; + std::atomic _shuttingDown{ false }; PointerEvent calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray, RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event, PointerEvent::EventType eventType); From 29106fbbbe422527fed7b5f10a6f57bea2528124 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 27 Mar 2018 14:18:19 -0700 Subject: [PATCH 32/45] Prevent potential double delete of QML overlays --- interface/src/ui/overlays/QmlOverlay.cpp | 32 ++++++++++++------------ interface/src/ui/overlays/QmlOverlay.h | 3 ++- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/interface/src/ui/overlays/QmlOverlay.cpp b/interface/src/ui/overlays/QmlOverlay.cpp index f4a9034187..2a583e0450 100644 --- a/interface/src/ui/overlays/QmlOverlay.cpp +++ b/interface/src/ui/overlays/QmlOverlay.cpp @@ -39,18 +39,20 @@ void QmlOverlay::buildQmlElement(const QUrl& url) { auto offscreenUi = DependencyManager::get(); offscreenUi->load(url, [=](QQmlContext* context, QObject* object) { - QQuickItem* rawPtr = dynamic_cast(object); - // Create a shared ptr with a custom deleter lambda, that calls deleteLater - _qmlElement = std::shared_ptr(rawPtr, [](QQuickItem* ptr) { - if (ptr) { - ptr->deleteLater(); - } - }); + _qmlElement = dynamic_cast(object); + connect(_qmlElement, &QObject::destroyed, this, &QmlOverlay::qmlElementDestroyed); }); } +void QmlOverlay::qmlElementDestroyed() { + _qmlElement = nullptr; +} + QmlOverlay::~QmlOverlay() { - _qmlElement.reset(); + if (_qmlElement) { + _qmlElement->deleteLater(); + } + _qmlElement = nullptr; } // QmlOverlay replaces Overlay's properties with those defined in the QML file used but keeps Overlay2D's properties. @@ -62,15 +64,13 @@ void QmlOverlay::setProperties(const QVariantMap& properties) { Overlay2D::setProperties(properties); auto bounds = _bounds; - std::weak_ptr weakQmlElement = _qmlElement; // check to see if qmlElement still exists - auto qmlElement = weakQmlElement.lock(); - if (qmlElement) { - qmlElement->setX(bounds.left()); - qmlElement->setY(bounds.top()); - qmlElement->setWidth(bounds.width()); - qmlElement->setHeight(bounds.height()); - QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); + if (_qmlElement) { + _qmlElement->setX(bounds.left()); + _qmlElement->setY(bounds.top()); + _qmlElement->setWidth(bounds.width()); + _qmlElement->setHeight(bounds.height()); + QMetaObject::invokeMethod(_qmlElement, "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties)); } } diff --git a/interface/src/ui/overlays/QmlOverlay.h b/interface/src/ui/overlays/QmlOverlay.h index ced2b6fa1f..7f2cf5a918 100644 --- a/interface/src/ui/overlays/QmlOverlay.h +++ b/interface/src/ui/overlays/QmlOverlay.h @@ -32,10 +32,11 @@ public: void render(RenderArgs* args) override; private: + Q_INVOKABLE void qmlElementDestroyed(); Q_INVOKABLE void buildQmlElement(const QUrl& url); protected: - std::shared_ptr _qmlElement; + QQuickItem* _qmlElement{ nullptr }; }; #endif // hifi_QmlOverlay_h From 9f3b82a417051c221b2cd533585f7a827959935e Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 27 Mar 2018 18:21:14 -0700 Subject: [PATCH 33/45] added the functions triggerVerticalRecenter,triggerHorizontalRecenter,and triggerRotationRecenter to MyAvatar.h, these allow java script calls to recenter the avatar on the fly --- interface/src/avatar/MyAvatar.cpp | 46 ++++++++++++++++++++++++++++++- interface/src/avatar/MyAvatar.h | 28 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9620a2dcec..b98620cbcb 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2760,6 +2760,27 @@ bool MyAvatar::isDriveKeyDisabled(DriveKeys key) const { } } +void MyAvatar::triggerVerticalRecenter() { + //do something here + _follow._forceActivateVertical = true; + + +} + +void MyAvatar::triggerHorizontalRecenter() { + //do something here + _follow._forceActivateHorizontal = true; + + +} + +void MyAvatar::triggerRotationRecenter() { + //do something here + _follow._forceActivateRotation = true; + + +} + // old school meat hook style glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { glm::vec3 headPosition; @@ -2953,7 +2974,9 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) { bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); + return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; + } bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -2970,13 +2993,16 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const float MAX_FORWARD_LEAN = 0.15f; const float MAX_BACKWARD_LEAN = 0.1f; + if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { return true; - } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { + } + else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { return true; } return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; + } bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -2984,6 +3010,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co const float CYLINDER_BOTTOM = -1.5f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } @@ -3002,6 +3029,23 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat activate(Vertical); } } + else { + if (!isActive(Rotation) && _forceActivateRotation) { + activate(Rotation); + _forceActivateRotation = false; + qCDebug(interfaceapp) << "the rotation property is activated+++++++++++++++++++++++" << endl; + } + if (!isActive(Horizontal) && _forceActivateHorizontal) { + activate(Horizontal); + _forceActivateHorizontal = false; + qCDebug(interfaceapp) << "the horizontal property is activated+++++++++++++++++++++++" << endl; + } + if (!isActive(Vertical) && _forceActivateVertical) { + activate(Vertical); + _forceActivateVertical = false; + qCDebug(interfaceapp) << "the vertical property is activated+++++++++++++++++++++++" << endl; + } + } glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * desiredBodyMatrix; glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5ca010d128..c3136b14c2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -104,6 +104,9 @@ class MyAvatar : public Avatar { * @property rightHandTipPose {Pose} READ-ONLY. Returns a pose offset 30 cm from MyAvatar.rightHandPose * @property hmdLeanRecenterEnabled {bool} This can be used disable the hmd lean recenter behavior. This behavior is what causes your avatar * to follow your HMD as you walk around the room, in room scale VR. Disabling this is useful if you desire to pin the avatar to a fixed location. + * @property hmdVerticalRecenterEnabled {bool} This can be used to turn vertical recenter off and on. + * @property hmdHorizontalRecenterEnabled {bool} This can be used to turn horizontal recenter off and on. + * @property hmdRotationRecenterEnabled {bool} This can be used to turn rotational recenter off and on. * @property collisionsEnabled {bool} This can be used to disable collisions between the avatar and the world. * @property useAdvancedMovementControls {bool} Stores the user preference only, does not change user mappings, this is done in the defaultScript * "scripts/system/controllers/toggleAdvancedMovementForHandControllers.js". @@ -149,6 +152,9 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool isAway READ getIsAway WRITE setAway) Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) + Q_PROPERTY(bool hmdVerticalRecenterEnabled READ getHMDVerticalRecenterEnabled WRITE setHMDVerticalRecenterEnabled) + Q_PROPERTY(bool hmdHorizontalRecenterEnabled READ getHMDHorizontalRecenterEnabled WRITE setHMDHorizontalRecenterEnabled) + Q_PROPERTY(bool hmdRotationRecenterEnabled READ getHMDRotationRecenterEnabled WRITE setHMDRotationRecenterEnabled) Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled) Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls) @@ -374,6 +380,15 @@ public: Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; } Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; } + Q_INVOKABLE void setHMDVerticalRecenterEnabled(bool value) { _hmdVerticalRecenterEnabled = value; } + Q_INVOKABLE bool getHMDVerticalRecenterEnabled() const { return _hmdVerticalRecenterEnabled; } + + Q_INVOKABLE void setHMDHorizontalRecenterEnabled(bool value) { _hmdHorizontalRecenterEnabled = value; } + Q_INVOKABLE bool getHMDHorizontalRecenterEnabled() const { return _hmdHorizontalRecenterEnabled; } + + Q_INVOKABLE void setHMDRotationRecenterEnabled(bool value) { _hmdRotationRecenterEnabled = value; } + Q_INVOKABLE bool getHMDRotationRecenterEnabled() const { return _hmdRotationRecenterEnabled; } + bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); } void setUseAdvancedMovementControls(bool useAdvancedMovementControls) { _useAdvancedMovementControls.set(useAdvancedMovementControls); } @@ -403,6 +418,10 @@ public: Q_INVOKABLE void enableDriveKey(DriveKeys key); Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const; + Q_INVOKABLE void triggerVerticalRecenter(); + Q_INVOKABLE void triggerHorizontalRecenter(); + Q_INVOKABLE void triggerRotationRecenter(); + eyeContactTarget getEyeContactTarget(); const MyHead* getMyHead() const; @@ -802,6 +821,12 @@ private: bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); + bool getForceActivateRotation(); + bool getForceActivateVertical(); + bool getForceActivateHorizontal(); + bool _forceActivateRotation{ false }; + bool _forceActivateVertical{ false }; + bool _forceActivateHorizontal{ false }; }; FollowHelper _follow; @@ -837,6 +862,9 @@ private: mutable std::mutex _controllerPoseMapMutex; bool _hmdLeanRecenterEnabled = true; + bool _hmdVerticalRecenterEnabled = true; + bool _hmdHorizontalRecenterEnabled = true; + bool _hmdRotationRecenterEnabled = true; AnimPose _prePhysicsRoomPose; std::mutex _holdActionsMutex; std::vector _holdActions; From aacfe927518d941ac8e024602f1266471e0ac6d3 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 28 Mar 2018 09:09:56 -0700 Subject: [PATCH 34/45] Don't trigger crashes from timers while waiting for some operation on exit --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 968af3e298..56068fba68 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7488,7 +7488,7 @@ DisplayPluginPointer Application::getActiveDisplayPlugin() const { return _displayPlugin; } - if (!_displayPlugin) { + if (!_aboutToQuit && !_displayPlugin) { const_cast(this)->updateDisplayMode(); Q_ASSERT(_displayPlugin); } From 9be162de95293d911cbaddfb1e772c53e4599ddf Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 28 Mar 2018 09:13:46 -0700 Subject: [PATCH 35/45] Synchronously shut down QML rendering threads --- libraries/qml/src/qml/impl/SharedObject.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp index f2af5bd036..d66f0f1dab 100644 --- a/libraries/qml/src/qml/impl/SharedObject.cpp +++ b/libraries/qml/src/qml/impl/SharedObject.cpp @@ -69,6 +69,7 @@ SharedObject::SharedObject() { _quickWindow->setColor(QColor(255, 255, 255, 0)); _quickWindow->setClearBeforeRendering(true); + QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &SharedObject::onAboutToQuit); } @@ -124,6 +125,7 @@ void SharedObject::setRootItem(QQuickItem* rootItem) { _renderThread->setObjectName(objectName()); _renderThread->start(); + // Create event handler for the render thread _renderObject = new RenderEventHandler(this, _renderThread); QCoreApplication::postEvent(this, new OffscreenEvent(OffscreenEvent::Initialize)); @@ -152,9 +154,16 @@ void SharedObject::destroy() { QObject::disconnect(_renderControl); QObject::disconnect(qApp); - QMutexLocker lock(&_mutex); - _quit = true; - QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit)); + { + QMutexLocker lock(&_mutex); + _quit = true; + QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit), Qt::HighEventPriority); + } + // Block until the rendering thread has stopped + // FIXME this is undesirable because this is blocking the main thread, + // but I haven't found a reliable way to do this only at application + // shutdown + _renderThread->wait(); } From 95f1d0e4fab16d91b65042090f7981d3527fbba0 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 28 Mar 2018 10:33:00 -0700 Subject: [PATCH 36/45] added get and set functions for the activate recenter variables --- interface/src/avatar/MyAvatar.cpp | 58 +++++++++++++++++++------------ interface/src/avatar/MyAvatar.h | 22 +++--------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b98620cbcb..2a523e9b9e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2761,24 +2761,15 @@ bool MyAvatar::isDriveKeyDisabled(DriveKeys key) const { } void MyAvatar::triggerVerticalRecenter() { - //do something here - _follow._forceActivateVertical = true; - - + _follow.setForceActivateVertical(true); } void MyAvatar::triggerHorizontalRecenter() { - //do something here - _follow._forceActivateHorizontal = true; - - + _follow.setForceActivateHorizontal(true); } void MyAvatar::triggerRotationRecenter() { - //do something here - _follow._forceActivateRotation = true; - - + _follow.setForceActivateRotation(true); } // old school meat hook style @@ -3028,22 +3019,19 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); } - } - else { - if (!isActive(Rotation) && _forceActivateRotation) { + } else { + //qCDebug(interfaceapp) << "turned off the recenter" << endl; + if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); - _forceActivateRotation = false; - qCDebug(interfaceapp) << "the rotation property is activated+++++++++++++++++++++++" << endl; + setForceActivateRotation(false); } - if (!isActive(Horizontal) && _forceActivateHorizontal) { + if (!isActive(Horizontal) && getForceActivateHorizontal()) { activate(Horizontal); - _forceActivateHorizontal = false; - qCDebug(interfaceapp) << "the horizontal property is activated+++++++++++++++++++++++" << endl; + setForceActivateHorizontal(false); } - if (!isActive(Vertical) && _forceActivateVertical) { + if (!isActive(Vertical) && getForceActivateVertical()) { activate(Vertical); - _forceActivateVertical = false; - qCDebug(interfaceapp) << "the vertical property is activated+++++++++++++++++++++++" << endl; + setForceActivateVertical(false); } } @@ -3094,6 +3082,30 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co } } +bool MyAvatar::FollowHelper::getForceActivateRotation() { + return _forceActivateRotation; +} + +void MyAvatar::FollowHelper::setForceActivateRotation(bool val) { + _forceActivateRotation = val; +} + +bool MyAvatar::FollowHelper::getForceActivateVertical() { + return _forceActivateVertical; +} + +void MyAvatar::FollowHelper::setForceActivateVertical(bool val) { + _forceActivateVertical = val; +} + +bool MyAvatar::FollowHelper::getForceActivateHorizontal() { + return _forceActivateHorizontal; +} + +void MyAvatar::FollowHelper::setForceActivateHorizontal(bool val) { + _forceActivateHorizontal = val; +} + float MyAvatar::getAccelerationEnergy() { glm::vec3 velocity = getWorldVelocity(); int changeInVelocity = abs(velocity.length() - priorVelocity.length()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c3136b14c2..6f7caa5c7d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -104,9 +104,6 @@ class MyAvatar : public Avatar { * @property rightHandTipPose {Pose} READ-ONLY. Returns a pose offset 30 cm from MyAvatar.rightHandPose * @property hmdLeanRecenterEnabled {bool} This can be used disable the hmd lean recenter behavior. This behavior is what causes your avatar * to follow your HMD as you walk around the room, in room scale VR. Disabling this is useful if you desire to pin the avatar to a fixed location. - * @property hmdVerticalRecenterEnabled {bool} This can be used to turn vertical recenter off and on. - * @property hmdHorizontalRecenterEnabled {bool} This can be used to turn horizontal recenter off and on. - * @property hmdRotationRecenterEnabled {bool} This can be used to turn rotational recenter off and on. * @property collisionsEnabled {bool} This can be used to disable collisions between the avatar and the world. * @property useAdvancedMovementControls {bool} Stores the user preference only, does not change user mappings, this is done in the defaultScript * "scripts/system/controllers/toggleAdvancedMovementForHandControllers.js". @@ -152,9 +149,6 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool isAway READ getIsAway WRITE setAway) Q_PROPERTY(bool hmdLeanRecenterEnabled READ getHMDLeanRecenterEnabled WRITE setHMDLeanRecenterEnabled) - Q_PROPERTY(bool hmdVerticalRecenterEnabled READ getHMDVerticalRecenterEnabled WRITE setHMDVerticalRecenterEnabled) - Q_PROPERTY(bool hmdHorizontalRecenterEnabled READ getHMDHorizontalRecenterEnabled WRITE setHMDHorizontalRecenterEnabled) - Q_PROPERTY(bool hmdRotationRecenterEnabled READ getHMDRotationRecenterEnabled WRITE setHMDRotationRecenterEnabled) Q_PROPERTY(bool collisionsEnabled READ getCollisionsEnabled WRITE setCollisionsEnabled) Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls) @@ -380,15 +374,6 @@ public: Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; } Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; } - Q_INVOKABLE void setHMDVerticalRecenterEnabled(bool value) { _hmdVerticalRecenterEnabled = value; } - Q_INVOKABLE bool getHMDVerticalRecenterEnabled() const { return _hmdVerticalRecenterEnabled; } - - Q_INVOKABLE void setHMDHorizontalRecenterEnabled(bool value) { _hmdHorizontalRecenterEnabled = value; } - Q_INVOKABLE bool getHMDHorizontalRecenterEnabled() const { return _hmdHorizontalRecenterEnabled; } - - Q_INVOKABLE void setHMDRotationRecenterEnabled(bool value) { _hmdRotationRecenterEnabled = value; } - Q_INVOKABLE bool getHMDRotationRecenterEnabled() const { return _hmdRotationRecenterEnabled; } - bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); } void setUseAdvancedMovementControls(bool useAdvancedMovementControls) { _useAdvancedMovementControls.set(useAdvancedMovementControls); } @@ -822,8 +807,11 @@ private: void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation(); + void setForceActivateRotation(bool val); bool getForceActivateVertical(); + void setForceActivateVertical(bool val); bool getForceActivateHorizontal(); + void setForceActivateHorizontal(bool val); bool _forceActivateRotation{ false }; bool _forceActivateVertical{ false }; bool _forceActivateHorizontal{ false }; @@ -862,9 +850,7 @@ private: mutable std::mutex _controllerPoseMapMutex; bool _hmdLeanRecenterEnabled = true; - bool _hmdVerticalRecenterEnabled = true; - bool _hmdHorizontalRecenterEnabled = true; - bool _hmdRotationRecenterEnabled = true; + AnimPose _prePhysicsRoomPose; std::mutex _holdActionsMutex; std::vector _holdActions; From 0175028a88bbf0f4d4bed67a365a3b2681971bee Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 28 Mar 2018 11:31:51 -0700 Subject: [PATCH 37/45] Ensure location is correctly updated when replacing set from Checkout page --- interface/resources/qml/hifi/commerce/checkout/Checkout.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 2502498942..c0cf45d292 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -96,6 +96,7 @@ Rectangle { root.activeView = "checkoutFailure"; UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message); } else { + root.certificateId = result.data.certificate_id; root.itemHref = result.data.download_url; if (result.data.categories.indexOf("Wearables") > -1) { root.itemType = "wearable"; From 90d87c5b5d6dacf6a106e5a24aab44ecc393c5cc Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 28 Mar 2018 14:00:36 -0700 Subject: [PATCH 38/45] changed get functions to const in MyAvatar.cpp changed bool variables to atomic for thread safety --- interface/src/avatar/MyAvatar.cpp | 10 ++++------ interface/src/avatar/MyAvatar.h | 12 ++++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 46dad99bb5..a9cab9582d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2991,8 +2991,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { return true; - } - else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { + } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { return true; } @@ -3024,7 +3023,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat activate(Vertical); } } else { - //qCDebug(interfaceapp) << "turned off the recenter" << endl; if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); setForceActivateRotation(false); @@ -3086,7 +3084,7 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co } } -bool MyAvatar::FollowHelper::getForceActivateRotation() { +bool MyAvatar::FollowHelper::getForceActivateRotation() const { return _forceActivateRotation; } @@ -3094,7 +3092,7 @@ void MyAvatar::FollowHelper::setForceActivateRotation(bool val) { _forceActivateRotation = val; } -bool MyAvatar::FollowHelper::getForceActivateVertical() { +bool MyAvatar::FollowHelper::getForceActivateVertical() const { return _forceActivateVertical; } @@ -3102,7 +3100,7 @@ void MyAvatar::FollowHelper::setForceActivateVertical(bool val) { _forceActivateVertical = val; } -bool MyAvatar::FollowHelper::getForceActivateHorizontal() { +bool MyAvatar::FollowHelper::getForceActivateHorizontal() const { return _forceActivateHorizontal; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8644a277c0..6a9d53e6f4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -807,15 +807,15 @@ private: bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); - bool getForceActivateRotation(); + bool getForceActivateRotation() const; void setForceActivateRotation(bool val); - bool getForceActivateVertical(); + bool getForceActivateVertical() const; void setForceActivateVertical(bool val); - bool getForceActivateHorizontal(); + bool getForceActivateHorizontal() const; void setForceActivateHorizontal(bool val); - bool _forceActivateRotation{ false }; - bool _forceActivateVertical{ false }; - bool _forceActivateHorizontal{ false }; + std::atomic _forceActivateRotation{ false }; + std::atomic _forceActivateVertical{ false }; + std::atomic _forceActivateHorizontal{ false }; }; FollowHelper _follow; From 2ee0af03c8fd14b43ead453f06933dbfc61f5a02 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 28 Mar 2018 16:17:55 -0700 Subject: [PATCH 39/45] Add an extra sanity check when calling fetchMetaSubItems when the subItems is not allocated yet --- libraries/render/src/render/Item.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index ed052adf6e..9c5efb9fa7 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -118,9 +118,15 @@ uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) c auto numSubs = fetchMetaSubItems(subItems); for (auto id : subItems) { - auto& item = scene.getItem(id); - if (item.exist()) { - subItemBounds.emplace_back(id, item.getBound()); + // TODO: Adding an extra check here even thought we shouldn't have too. + // We have cases when the id returned by fetchMetaSubItems is not allocated + if (scene.isAllocatedID(id)) { + auto& item = scene.getItem(id); + if (item.exist()) { + subItemBounds.emplace_back(id, item.getBound()); + } else { + numSubs--; + } } else { numSubs--; } From 387ff680d5dbe989eac0056f95a660bd29f47dae Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Wed, 28 Mar 2018 18:12:30 -0700 Subject: [PATCH 40/45] support deleted scenario --- interface/resources/qml/hifi/tablet/NewModelDialog.qml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index ec8289d68e..5216bf45d5 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -73,7 +73,11 @@ Rectangle { } onTextChanged : { - button1.enabled = true; + if (modelURL.text.length === 0){ + button1.enabled = false; + } else { + button1.enabled = true; + } } MouseArea { From 3f44b88d2d5d512d4dedcfa988b1951e76dca4a1 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 29 Mar 2018 10:09:51 -0700 Subject: [PATCH 41/45] added js documentation for the three trigger recenter functionsthat have been added to MyAvatar class --- interface/src/avatar/MyAvatar.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6a9d53e6f4..118f14e71b 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -404,6 +404,28 @@ public: Q_INVOKABLE void enableDriveKey(DriveKeys key); Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const; + /**jsdoc + *The triggerVerticalRecenter function activates one time the recentering + *behaviour in the vertical direction. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerVerticalRecenter + * + */ + + /**jsdoc + *The triggerHorizontalRecenter function activates one time the recentering behaviour + *in the horizontal direction. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerHorizontalRecenter + */ + + /**jsdoc + *The triggerRotationRecenter function activates one time the recentering behaviour + *in the rotation of the root of the avatar. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerRotationRecenter + */ + Q_INVOKABLE void triggerVerticalRecenter(); Q_INVOKABLE void triggerHorizontalRecenter(); Q_INVOKABLE void triggerRotationRecenter(); From 420672a7690d1ccaf4fb070812bc9abbc7c11f6f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:26:05 -0700 Subject: [PATCH 42/45] fix-qml-confict --- interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} | 1 + scripts/developer/utilities/audio/audioScope.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} (99%) diff --git a/interface/resources/qml/AudioScope.qml b/interface/resources/qml/AudioScopeUI.qml similarity index 99% rename from interface/resources/qml/AudioScope.qml rename to interface/resources/qml/AudioScopeUI.qml index aa181dbf8d..b009c249bc 100644 --- a/interface/resources/qml/AudioScope.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,6 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit +import "." as HifiRoot Item { id: root diff --git a/scripts/developer/utilities/audio/audioScope.js b/scripts/developer/utilities/audio/audioScope.js index 00c9e4b725..63cbf0a6e2 100644 --- a/scripts/developer/utilities/audio/audioScope.js +++ b/scripts/developer/utilities/audio/audioScope.js @@ -1,4 +1,4 @@ -var qml = Script.resourcesPath() + '/qml/AudioScope.qml'; +var qml = Script.resourcesPath() + '/qml/AudioScopeUI.qml'; var window = new OverlayWindow({ title: 'Audio Scope', source: qml, @@ -14,4 +14,4 @@ window.closed.connect(function () { AudioScope.setServerEcho(false); AudioScope.selectAudioScopeFiveFrames(); Script.stop(); -}); \ No newline at end of file +}); From f7a081c9ecf6180c848697041bf519a033da08cb Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:29:01 -0700 Subject: [PATCH 43/45] minimize diff --- interface/resources/qml/AudioScopeUI.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/AudioScopeUI.qml b/interface/resources/qml/AudioScopeUI.qml index b009c249bc..aa181dbf8d 100644 --- a/interface/resources/qml/AudioScopeUI.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,7 +12,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit -import "." as HifiRoot Item { id: root From bd6dbadadee749a6fd86efbbf01367221e0573d9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 30 Mar 2018 10:18:03 -0700 Subject: [PATCH 44/45] No magic numbers --- assignment-client/src/entities/EntityServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 1862287b6d..01d48cb0b2 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -489,7 +489,7 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/1000)) { + if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); tree->deleteEntity(i.value(), true); From 59fb448698f8276d6fa813a55033b1bb661ff0c9 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 30 Mar 2018 10:28:40 -0700 Subject: [PATCH 45/45] Remove duplicate function --- assignment-client/src/entities/EntityServer.cpp | 2 +- libraries/entities/src/EntityItem.h | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 01d48cb0b2..d2bcbf2886 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -489,7 +489,7 @@ void EntityServer::startDynamicDomainVerification() { if (networkReply->error() == QNetworkReply::NoError) { if (jsonObject["domain_id"].toString() != thisDomainID) { - if (entity->getCreatedAgo() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { + if (entity->getAge() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); tree->deleteEntity(i.value(), true); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 962babb558..0303964e18 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -222,10 +222,6 @@ public: quint64 getCreated() const; /// get the created-time in useconds for the entity void setCreated(quint64 value); /// set the created-time in useconds for the entity - float getCreatedAgo() const /// Elapsed seconds since this entity was created - { - return (float)(usecTimestampNow() - getCreated()) / (float)USECS_PER_SECOND; - } /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME; }