From def2b4e6adefddcdb421f1a952d120bb6bf61fd3 Mon Sep 17 00:00:00 2001 From: David Steele Date: Wed, 19 Apr 2023 17:22:49 +0100 Subject: [PATCH] [Tizen] Enabled sampler arrays in shader Previously, texture units were only bound to the first element of any sampler array. Modified the shader reflection parser to find sampler arrays of the format uniform sampler2D mySamplers[16] and store the number of elements in the sampler code. Modified the binding code to ensure that textures are bound to each element of a sampler array. Made several assumptions in this code: A) that GL returns sequential locations for each uniform array element (It doesn't guarantee a strict sequence, but in practice, this is the case). B) that the dali-core implementation binds texture units in the order 0..N-1 with a binding index of 0..N-1. (A safe assumption, given we know how dali-core works!) Note, we don't really use locations for non-sampler uniform array elements, either, we just offset from the first location. Change-Id: I68c61f3e22303271d5d916c3588f4a3bd5898757 Signed-off-by: David Steele --- dali/internal/graphics/gles-impl/gles-context.cpp | 32 ++++++++++----- .../gles-impl/gles-graphics-reflection.cpp | 48 ++++++++++++++++++---- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/dali/internal/graphics/gles-impl/gles-context.cpp b/dali/internal/graphics/gles-impl/gles-context.cpp index c6f0728..56625a0 100644 --- a/dali/internal/graphics/gles-impl/gles-context.cpp +++ b/dali/internal/graphics/gles-impl/gles-context.cpp @@ -305,6 +305,12 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: // Map binding# to sampler location const auto& reflection = !newProgram ? currentProgram->GetReflection() : newProgram->GetReflection(); const auto& samplers = reflection.GetSamplers(); + + uint32_t currentSampler = 0; + uint32_t currentElement = 0; + + // @warning Assume that binding.binding is strictly linear in the same order as mCurrentTextureBindings + // elements. This avoids having to sort the bindings. for(const auto& binding : mImpl->mCurrentTextureBindings) { auto texture = const_cast(static_cast(binding.texture)); @@ -312,24 +318,28 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: // Texture may not have been initialized yet...(tbm_surface timing issue?) if(!texture->GetGLTexture()) { - // Attempt to reinitialize - // @todo need to put this somewhere else where it isn't const. - // Maybe post it back on end of initialize queue if initialization fails? texture->InitializeResource(); } // Warning, this may cause glWaitSync to occur on the GPU. dependencyChecker.CheckNeedsSync(this, texture); - texture->Bind(binding); - - texture->Prepare(); // @todo also non-const. - - if(binding.binding < samplers.size()) // binding maps to texture unit. (texture bindings should also be in binding order) + texture->Prepare(); + + // @warning Assume that location of array elements is sequential. + // @warning GL does not guarantee this, but in practice, it is. + gl.Uniform1i(samplers[currentSampler].location + currentElement, + samplers[currentSampler].offset + currentElement); + ++currentElement; + if(currentElement >= samplers[currentSampler].elementCount) + { + ++currentSampler; + currentElement = 0; + } + if(currentSampler >= samplers.size()) { - // Offset is set to the lexical offset within the frag shader, map it to the texture unit - // @todo Explicitly set the texture unit through the graphics interface - gl.Uniform1i(samplers[binding.binding].location, samplers[binding.binding].offset); + // Don't bind more textures than there are active samplers. + break; } } diff --git a/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp b/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp index f3e15cb..76f305a 100644 --- a/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp +++ b/dali/internal/graphics/gles-impl/gles-graphics-reflection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,7 +60,8 @@ bool operator==(const StringSize& lhs, const char* rhs) return strncmp(lhs.mString, rhs, lhs.mLength) == 0; } -const char* const DELIMITERS = " \t\n"; +const char* const DELIMITERS = " \t\n"; +const char* const DELIMITERS_INC_INDEX = " \t\n[]"; constexpr StringSize UNIFORM{"uniform"}; constexpr StringSize SAMPLER_PREFIX{"sampler"}; constexpr StringSize SAMPLER_TYPES[] = {"2D", "Cube", "ExternalOES"}; @@ -148,27 +149,50 @@ void ParseShaderSamplers(std::string shaderSource, std::vector(uniformOpaques.size()); ++i) { if(samplerPositions[i] == -1 && strncmp(token, uniformOpaques[i].name.c_str(), uniformOpaques[i].name.size()) == 0) { - samplerPositions[i] = uniformOpaques[i].offset = samplerPosition++; - found = true; + // We have found a matching name. + samplerPositions[i] = uniformOpaques[i].offset = samplerPosition; + if(arraySize == 0) + { + ++samplerPosition; + } + else + { + samplerPosition += arraySize; + } + found = true; break; } } @@ -288,6 +312,7 @@ void Reflection::BuildUniformReflection() GLenum type; int written; gl->GetActiveUniform(glProgram, i, maxLen, &written, &elementCount, &type, name); + int location = gl->GetUniformLocation(glProgram, name); Dali::Graphics::UniformInfo uniformInfo; @@ -295,16 +320,21 @@ void Reflection::BuildUniformReflection() uniformInfo.name = name; if(elementCount > 1) { + // If we have an active uniform that refers to an array, only the first element + // is present in this list, and is referenced as "uniform[0]", but the element + // count is non-zero to indicate how many uniforms there are in the array. + + // Strip off the array, but store the element count auto iter = std::string(uniformInfo.name).find("[", 0); if(iter != std::string::npos) { - uniformInfo.name = std::string(name).substr(0, iter); + uniformInfo.name = std::string(name).substr(0, iter); + uniformInfo.elementCount = elementCount; } } - uniformInfo.uniformClass = IsSampler(type) ? Dali::Graphics::UniformClass::COMBINED_IMAGE_SAMPLER : Dali::Graphics::UniformClass::UNIFORM; - uniformInfo.location = location; //IsSampler(type) ? 0 : location; - uniformInfo.binding = 0; // IsSampler(type) ? location : 0; + uniformInfo.location = location; // GL doesn't guarantee that consecutive array elements have sequential locations. But, we only store location of first element. + uniformInfo.binding = 0; uniformInfo.bufferIndex = 0; uniformInfo.offset = 0; -- 2.7.4