From ea23d8283ff5a0c80bdb2e499bf356dab36c29e4 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Jan 2017 16:02:58 -0800 Subject: [PATCH 01/10] 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/10] 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/10] 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/10] 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 b7d0260a17654dd79854e5b65058b2cd74c6115f Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 8 Feb 2018 14:05:21 -0800 Subject: [PATCH 05/10] 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 06/10] 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 07/10] 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 08/10] 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 09/10] 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 c793a8d2c0bf7304a06e4e2b315e7fe03101f3a0 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 12 Mar 2018 12:28:12 -0700 Subject: [PATCH 10/10] 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 }; }; }