WebGLShader.cpp (5947B)
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "WebGLShader.h" 7 8 #include "GLContext.h" 9 #include "GLSLANG/ShaderLang.h" 10 #include "WebGLContext.h" 11 #include "WebGLObjectModel.h" 12 #include "WebGLShaderValidator.h" 13 #include "WebGLValidateStrings.h" 14 #include "mozilla/MemoryReporting.h" 15 #include "mozilla/dom/WebGLRenderingContextBinding.h" 16 #include "nsPrintfCString.h" 17 #include "nsString.h" 18 #include "prenv.h" 19 20 namespace mozilla { 21 22 static void PrintLongString(const char* const begin, const size_t len) { 23 // Wow - Roll Your Own Foreach-Lines because printf_stderr has a hard-coded 24 // internal size, so long strings are truncated. 25 26 const size_t chunkSize = 1000; 27 auto buf = std::vector<char>(chunkSize + 1); // +1 for null-term 28 const auto bufBegin = buf.data(); 29 30 auto chunkBegin = begin; 31 const auto end = begin + len; 32 while (chunkBegin + chunkSize < end) { 33 memcpy(bufBegin, chunkBegin, chunkSize); 34 printf_stderr("%s", bufBegin); 35 chunkBegin += chunkSize; 36 } 37 printf_stderr("%s", chunkBegin); 38 } 39 40 template <size_t N> 41 static bool SubstringStartsWith(const std::string& testStr, size_t offset, 42 const char (&refStr)[N]) { 43 for (size_t i = 0; i < N - 1; i++) { 44 if (testStr[offset + i] != refStr[i]) return false; 45 } 46 return true; 47 } 48 49 static void GetCompilationStatusAndLog(gl::GLContext* gl, GLuint shader, 50 bool* const out_success, 51 std::string* const out_log) { 52 GLint compileStatus = LOCAL_GL_FALSE; 53 gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &compileStatus); 54 55 // It's simpler if we always get the log. 56 GLint lenWithNull = 0; 57 gl->fGetShaderiv(shader, LOCAL_GL_INFO_LOG_LENGTH, &lenWithNull); 58 if (lenWithNull < 1) { 59 lenWithNull = 1; 60 } 61 std::vector<char> buffer(lenWithNull); 62 gl->fGetShaderInfoLog(shader, buffer.size(), nullptr, buffer.data()); 63 *out_log = buffer.data(); 64 65 *out_success = (compileStatus == LOCAL_GL_TRUE); 66 } 67 68 //////////////////////////////////////////////////////////////////////////////// 69 70 WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type) 71 : WebGLContextBoundObject(webgl), 72 mGLName(webgl->gl->fCreateShader(type)), 73 mType(type) { 74 mCompileResults = std::make_unique<webgl::ShaderValidatorResults>(); 75 } 76 77 WebGLShader::~WebGLShader() { 78 if (!mContext) return; 79 mContext->gl->fDeleteShader(mGLName); 80 } 81 82 void WebGLShader::ShaderSource(const std::string& u8) { 83 mSource = CrushGlslToAscii(u8); 84 } 85 86 void WebGLShader::CompileShader() { 87 mCompilationSuccessful = false; 88 89 gl::GLContext* gl = mContext->gl; 90 91 static const bool kDumpShaders = PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS"); 92 if (MOZ_UNLIKELY(kDumpShaders)) { 93 printf_stderr("==== begin MOZ_WEBGL_DUMP_SHADERS ====\n"); 94 PrintLongString(mSource.c_str(), mSource.size()); 95 } 96 97 { 98 const auto validator = mContext->CreateShaderValidator(mType); 99 MOZ_ASSERT(validator); 100 101 mCompileResults = validator->ValidateAndTranslate(mSource.c_str()); 102 } 103 104 mCompilationLog = mCompileResults->mInfoLog.c_str(); 105 const auto& success = mCompileResults->mValid; 106 107 if (MOZ_UNLIKELY(kDumpShaders)) { 108 printf_stderr("\n==== \\/ \\/ \\/ ====\n"); 109 if (success) { 110 const auto& translated = mCompileResults->mObjectCode; 111 PrintLongString(translated.data(), translated.size()); 112 } else { 113 printf_stderr("Validation failed:\n%s", 114 mCompileResults->mInfoLog.c_str()); 115 } 116 printf_stderr("\n==== end ====\n"); 117 } 118 119 if (!success) return; 120 121 const std::array<const char*, 1> parts = { 122 mCompileResults->mObjectCode.c_str()}; 123 gl->fShaderSource(mGLName, parts.size(), parts.data(), nullptr); 124 125 gl->fCompileShader(mGLName); 126 127 GetCompilationStatusAndLog(gl, mGLName, &mCompilationSuccessful, 128 &mCompilationLog); 129 } 130 131 //////////////////////////////////////////////////////////////////////////////// 132 133 size_t WebGLShader::CalcNumSamplerUniforms() const { 134 size_t accum = 0; 135 for (const auto& cur : mCompileResults->mUniforms) { 136 const auto& type = cur.type; 137 if (type == LOCAL_GL_SAMPLER_2D || type == LOCAL_GL_SAMPLER_CUBE) { 138 accum += cur.getArraySizeProduct(); 139 } 140 } 141 return accum; 142 } 143 144 size_t WebGLShader::NumAttributes() const { 145 return mCompileResults->mAttributes.size(); 146 } 147 148 void WebGLShader::BindAttribLocation(GLuint prog, const std::string& userName, 149 GLuint index) const { 150 for (const auto& attrib : mCompileResults->mAttributes) { 151 if (attrib.name == userName) { 152 mContext->gl->fBindAttribLocation(prog, index, attrib.mappedName.c_str()); 153 return; 154 } 155 } 156 } 157 158 void WebGLShader::MapTransformFeedbackVaryings( 159 const std::vector<std::string>& varyings, 160 std::vector<std::string>* out_mappedVaryings) const { 161 MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER); 162 MOZ_ASSERT(out_mappedVaryings); 163 164 out_mappedVaryings->clear(); 165 out_mappedVaryings->reserve(varyings.size()); 166 167 const auto& shaderVaryings = mCompileResults->mVaryings; 168 169 for (const auto& userName : varyings) { 170 const auto* mappedName = &userName; 171 for (const auto& shaderVarying : shaderVaryings) { 172 if (shaderVarying.name == userName) { 173 mappedName = &shaderVarying.mappedName; 174 break; 175 } 176 } 177 out_mappedVaryings->push_back(*mappedName); 178 } 179 } 180 181 //////////////////////////////////////////////////////////////////////////////// 182 // Boilerplate 183 184 size_t WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const { 185 return mallocSizeOf(this) + mSource.size() + 1 + 186 mCompileResults->SizeOfIncludingThis(mallocSizeOf) + 187 mCompilationLog.size() + 1; 188 } 189 190 } // namespace mozilla