diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp index 3913311d17..c24e447cff 100644 --- a/filament/src/Engine.cpp +++ b/filament/src/Engine.cpp @@ -452,8 +452,8 @@ Handle FEngine::createPostProcessProgram(MaterialParser& parser, Program pb; pb .diagnostics(CString("Post Process")) .withSamplerBindings(pBindings) - .withVertexShader(vShaderBuilder.getShader()) - .withFragmentShader(fShaderBuilder.getShader()) + .withVertexShader(vShaderBuilder.data(), vShaderBuilder.size()) + .withFragmentShader(fShaderBuilder.data(), fShaderBuilder.size()) .addUniformBlock(BindingPoints::PER_VIEW, &PerViewUib::getUib()) .addUniformBlock(BindingPoints::POST_PROCESS, &PostProcessingUib::getUib()) .addSamplerBlock(BindingPoints::POST_PROCESS, &PostProcessSib::getSib()); diff --git a/filament/src/Material.cpp b/filament/src/Material.cpp index cfefb164f7..0a77416466 100644 --- a/filament/src/Material.cpp +++ b/filament/src/Material.cpp @@ -316,8 +316,8 @@ Handle FMaterial::getProgramSlow(uint8_t variantKey) const noexcept { Program pb; pb .diagnostics(mName, variantKey) - .withVertexShader(vsBuilder.getShader()) - .withFragmentShader(fsBuilder.getShader()) + .withVertexShader(vsBuilder.data(), vsBuilder.size()) + .withFragmentShader(fsBuilder.data(), fsBuilder.size()) .withSamplerBindings(&mSamplerBindings) .addUniformBlock(BindingPoints::PER_VIEW, &UibGenerator::getPerViewUib()) .addUniformBlock(BindingPoints::LIGHTS, &UibGenerator::getLightsUib()) diff --git a/filament/src/driver/Program.cpp b/filament/src/driver/Program.cpp index d52fc9b81b..3939e88ddd 100644 --- a/filament/src/driver/Program.cpp +++ b/filament/src/driver/Program.cpp @@ -16,6 +16,9 @@ #include "driver/Program.h" +#include +#include + using namespace utils; namespace filament { @@ -49,13 +52,10 @@ Program& Program::withSamplerBindings(const SamplerBindingMap* bindings) { return *this; } -Program& Program::shader(Program::Shader shader, CString const& source) { - mShadersSource[size_t(shader)] = source; - return *this; -} - -Program& Program::shader(Program::Shader shader, CString&& source) noexcept { - source.swap(mShadersSource[size_t(shader)]); +Program& Program::shader(Program::Shader shader, void const* data, size_t size) noexcept { + std::vector blob(size); + std::copy_n((const uint8_t *)data, size, blob.data()); + mShadersSource[size_t(shader)] = std::move(blob); return *this; } diff --git a/filament/src/driver/Program.h b/filament/src/driver/Program.h index 4867e247ae..93c140191b 100644 --- a/filament/src/driver/Program.h +++ b/filament/src/driver/Program.h @@ -20,17 +20,18 @@ #include #include -#include -#include - #include #include #include #include +#include namespace filament { +class SamplerInterfaceBlock; +class UniformInterfaceBlock; + class Program { public: @@ -55,8 +56,7 @@ public: Program& diagnostics(utils::CString&& name, uint8_t variantKey = 0) noexcept; // sets one of the program's shader (e.g. vertex, fragment) - Program& shader(Shader shader, utils::CString const& source); - Program& shader(Shader shader, utils::CString&& source) noexcept; + Program& shader(Shader shader, void const* data, size_t size) noexcept; // sets a uniform interface block for this program Program& addUniformBlock(size_t index, const UniformInterfaceBlock* ib); @@ -64,20 +64,18 @@ public: // sets a sampler interface block for this program Program& addSamplerBlock(size_t index, const SamplerInterfaceBlock* ib); - template - Program& withVertexShader(T&& source) { - return shader(Shader::VERTEX, std::forward(source)); + Program& withVertexShader(void const* data, size_t size) { + return shader(Shader::VERTEX, data, size); } - template - Program& withFragmentShader(T&& source) { - return shader(Shader::FRAGMENT, std::forward(source)); + Program& withFragmentShader(void const* data, size_t size) { + return shader(Shader::FRAGMENT, data, size); } // sets up sampler bindings for this program Program& withSamplerBindings(const SamplerBindingMap* bindings); - std::array const& getShadersSource() const noexcept { + std::array, NUM_SHADER_TYPES> const& getShadersSource() const noexcept { return mShadersSource; } @@ -112,10 +110,12 @@ private: friend utils::io::ostream& operator<< (utils::io::ostream& out, const Program& builder); #endif + // FIXME: none of these fields should be public as this is a public API + std::array mUniformInterfaceBlocks; std::array mSamplerInterfaceBlocks; const SamplerBindingMap* mSamplerBindings = nullptr; - std::array mShadersSource; + std::array, NUM_SHADER_TYPES> mShadersSource; size_t mSamplerCount = 0; utils::CString mName; uint8_t mVariant; diff --git a/filament/src/driver/metal/MetalHandles.mm b/filament/src/driver/metal/MetalHandles.mm index 8c860b0ee4..da932984e3 100644 --- a/filament/src/driver/metal/MetalHandles.mm +++ b/filament/src/driver/metal/MetalHandles.mm @@ -204,7 +204,7 @@ MetalProgram::MetalProgram(id device, const Program& program) noexcep if (source.empty()) { continue; } - NSString* objcSource = [NSString stringWithCString:source.c_str() + NSString* objcSource = [NSString stringWithCString:(const char*)source.data() encoding:NSUTF8StringEncoding]; NSError* error = nil; id library = [device newLibraryWithSource:objcSource diff --git a/filament/src/driver/opengl/OpenGLProgram.cpp b/filament/src/driver/opengl/OpenGLProgram.cpp index 373cf97f6f..6e31e62ef4 100644 --- a/filament/src/driver/opengl/OpenGLProgram.cpp +++ b/filament/src/driver/opengl/OpenGLProgram.cpp @@ -16,14 +16,16 @@ #include "driver/opengl/OpenGLProgram.h" -#include -#include +#include +#include + +#include "driver/opengl/OpenGLDriver.h" #include #include #include -#include "driver/opengl/OpenGLDriver.h" +#include namespace filament { @@ -62,9 +64,9 @@ OpenGLProgram::OpenGLProgram(OpenGLDriver* gl, const Program& programBuilder) no break; } - if (shadersSource[i].length()) { + if (!shadersSource[i].empty()) { GLint status; - char const* const source = shadersSource[i].c_str(); + char const* const source = (const char*)shadersSource[i].data(); GLuint shaderId = glCreateShader(glShaderType); glShaderSource(shaderId, 1, &source, nullptr); diff --git a/filament/src/driver/vulkan/VulkanHandles.cpp b/filament/src/driver/vulkan/VulkanHandles.cpp index 7f841d01cb..89ab64b15a 100644 --- a/filament/src/driver/vulkan/VulkanHandles.cpp +++ b/filament/src/driver/vulkan/VulkanHandles.cpp @@ -61,7 +61,7 @@ VulkanProgram::VulkanProgram(VulkanContext& context, const Program& builder) noe VkShaderModuleCreateInfo moduleInfo = {}; moduleInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; moduleInfo.codeSize = blob.size(); - moduleInfo.pCode = (uint32_t*) blob.c_str(); + moduleInfo.pCode = (uint32_t*) blob.data(); VkResult result = vkCreateShaderModule(context.device, &moduleInfo, VKALLOC, module); ASSERT_POSTCONDITION(result == VK_SUCCESS, "Unable to create shader module."); } diff --git a/libs/filaflat/include/filaflat/ShaderBuilder.h b/libs/filaflat/include/filaflat/ShaderBuilder.h index dd1d95bb5c..7af0e772ab 100644 --- a/libs/filaflat/include/filaflat/ShaderBuilder.h +++ b/libs/filaflat/include/filaflat/ShaderBuilder.h @@ -27,6 +27,8 @@ namespace filaflat { class ShaderBuilder { public: ShaderBuilder(); + ShaderBuilder(ShaderBuilder const& rhs) = delete; + ShaderBuilder& operator=(ShaderBuilder const&rhs) = delete; ~ShaderBuilder(); // Before using a shader buffer to create a shader you should reset it. @@ -36,13 +38,10 @@ public: void announce(size_t size); // Append a data blob to the shader. Returns true if successful. - void appendPart(const char* data, size_t size) noexcept; + void append(const char* data, size_t size) noexcept; - // returns a copy of the shader string - utils::CString getShader() const { return { mShader, mCursor }; } - - // returns the shader string. valid until next api call. - char const* c_str() const noexcept { return mShader; } + // returns the shader blob. valid until next api call. + void const* data() const noexcept { return mShader; } size_t size() const { return mCursor; } diff --git a/libs/filaflat/src/MaterialChunk.cpp b/libs/filaflat/src/MaterialChunk.cpp index cb08d967dc..0a7fa7ec43 100644 --- a/libs/filaflat/src/MaterialChunk.cpp +++ b/libs/filaflat/src/MaterialChunk.cpp @@ -108,12 +108,12 @@ bool MaterialChunk::getTextShader(Unflattener unflattener, BlobDictionary& dicti return false; } const char* string = dictionary.getString(lineIndex); - shader.appendPart(string, strlen(string)); - shader.appendPart("\n", 1); + shader.append(string, strlen(string)); + shader.append("\n", 1); } // Write the terminating null character. - shader.appendPart("", 1); + shader.append("", 1); return true; } @@ -137,7 +137,7 @@ bool MaterialChunk::getSpirvShader(Unflattener unflattener, BlobDictionary& dict const char* shaderContent = dictionary.getBlob(index, &shaderSize); builder.reset(); builder.announce(shaderSize); - builder.appendPart(shaderContent, shaderSize); + builder.append(shaderContent, shaderSize); return true; } diff --git a/libs/filaflat/src/ShaderBuilder.cpp b/libs/filaflat/src/ShaderBuilder.cpp index 1879521721..7076f0841f 100644 --- a/libs/filaflat/src/ShaderBuilder.cpp +++ b/libs/filaflat/src/ShaderBuilder.cpp @@ -33,17 +33,16 @@ ShaderBuilder::~ShaderBuilder() { void ShaderBuilder::reset() { mCursor = 0; - mShader[0] = '\0'; } void ShaderBuilder::announce(size_t size) { if (size > mCapacity) { mCapacity = (uint32_t)size; - mShader = (char *)realloc(mShader, size); + mShader = (char*)realloc(mShader, size); } } -void ShaderBuilder::appendPart(const char* data, size_t size) noexcept { +void ShaderBuilder::append(const char* data, size_t size) noexcept { size_t available = mCapacity - mCursor; assert(size <= available); memcpy(mShader + mCursor, data, size); diff --git a/libs/utils/include/utils/CString.h b/libs/utils/include/utils/CString.h index d2b0b8e238..fe06a0b0c5 100644 --- a/libs/utils/include/utils/CString.h +++ b/libs/utils/include/utils/CString.h @@ -200,6 +200,7 @@ public: CString() noexcept = default; + // cstr must be a null terminated string and length == strlen(cstr) CString(const char* cstr, size_type length); template diff --git a/libs/utils/src/CString.cpp b/libs/utils/src/CString.cpp index a6023becd8..789b21f00c 100644 --- a/libs/utils/src/CString.cpp +++ b/libs/utils/src/CString.cpp @@ -35,9 +35,7 @@ int StaticString::compare(const StaticString& rhs) const noexcept { UTILS_NOINLINE CString::CString(const char* cstr, size_type length) { if (length && cstr) { - // I think we can't use this assert with vulkan, because shaders are returned as CString - // (see ShaderBuilder). - // assert(length == strlen(cstr)); + assert(length == strlen(cstr)); Data* p = (Data*)malloc(sizeof(Data) + length + 1); p->length = length; mCStr = (value_type*)(p + 1); diff --git a/tools/matinfo/src/main.cpp b/tools/matinfo/src/main.cpp index 049aae08d7..5462e181d8 100644 --- a/tools/matinfo/src/main.cpp +++ b/tools/matinfo/src/main.cpp @@ -909,7 +909,7 @@ static bool parseChunks(Config config, void* data, size_t size) { const auto& item = info[config.shaderIndex]; parser.getShader(item.shaderModel, item.variant, item.pipelineStage, builder); - std::cout << builder.c_str(); + std::cout << builder.data(); return true; } @@ -935,7 +935,7 @@ static bool parseChunks(Config config, void* data, size_t size) { parser.getShader(item.shaderModel, item.variant, item.pipelineStage, builder); // Build std::vector since that's what the Khronos libraries consume. - uint32_t const* words = reinterpret_cast(builder.c_str()); + uint32_t const* words = reinterpret_cast(builder.data()); assert(0 == (builder.size() % 4)); const std::vector spirv(words, words + builder.size() / 4); @@ -969,7 +969,7 @@ static bool parseChunks(Config config, void* data, size_t size) { const auto& item = info[config.shaderIndex]; parser.getShader(item.shaderModel, item.variant, item.pipelineStage, builder); - std::cout << builder.getShader().c_str(); + std::cout << builder.data(); return true; }