Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / canvas / WebGLShader.cpp
blob6bf480551121ce6bafe9bb5dbfd65fe9ee40b744
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/. */
6 #include "WebGLShader.h"
8 #include "GLSLANG/ShaderLang.h"
9 #include "GLContext.h"
10 #include "mozilla/dom/WebGLRenderingContextBinding.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "nsPrintfCString.h"
13 #include "nsString.h"
14 #include "prenv.h"
15 #include "WebGLContext.h"
16 #include "WebGLObjectModel.h"
17 #include "WebGLShaderValidator.h"
18 #include "WebGLValidateStrings.h"
20 namespace mozilla {
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.
26 const size_t chunkSize = 1000;
27 const UniqueBuffer buf(moz_xmalloc(chunkSize + 1)); // +1 for null-term
28 const auto bufBegin = (char*)buf.get();
29 bufBegin[chunkSize] = '\0';
31 auto chunkBegin = begin;
32 const auto end = begin + len;
33 while (chunkBegin + chunkSize < end) {
34 memcpy(bufBegin, chunkBegin, chunkSize);
35 printf_stderr("%s", bufBegin);
36 chunkBegin += chunkSize;
38 printf_stderr("%s", chunkBegin);
41 template <size_t N>
42 static bool SubstringStartsWith(const std::string& testStr, size_t offset,
43 const char (&refStr)[N]) {
44 for (size_t i = 0; i < N - 1; i++) {
45 if (testStr[offset + i] != refStr[i]) return false;
47 return true;
50 static void GetCompilationStatusAndLog(gl::GLContext* gl, GLuint shader,
51 bool* const out_success,
52 std::string* const out_log) {
53 GLint compileStatus = LOCAL_GL_FALSE;
54 gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &compileStatus);
56 // It's simpler if we always get the log.
57 GLint lenWithNull = 0;
58 gl->fGetShaderiv(shader, LOCAL_GL_INFO_LOG_LENGTH, &lenWithNull);
59 if (lenWithNull < 1) {
60 lenWithNull = 1;
62 std::vector<char> buffer(lenWithNull);
63 gl->fGetShaderInfoLog(shader, buffer.size(), nullptr, buffer.data());
64 *out_log = buffer.data();
66 *out_success = (compileStatus == LOCAL_GL_TRUE);
69 ////////////////////////////////////////////////////////////////////////////////
71 WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
72 : WebGLContextBoundObject(webgl),
73 mGLName(webgl->gl->fCreateShader(type)),
74 mType(type) {
75 mCompileResults = std::make_unique<webgl::ShaderValidatorResults>();
78 WebGLShader::~WebGLShader() {
79 if (!mContext) return;
80 mContext->gl->fDeleteShader(mGLName);
83 void WebGLShader::ShaderSource(const std::string& cleanSource) {
84 const auto badChar =
85 CheckGLSLPreprocString(mContext->IsWebGL2(), cleanSource);
86 MOZ_ASSERT(!badChar);
87 if (badChar) return;
88 mSource = cleanSource;
91 void WebGLShader::CompileShader() {
92 mCompilationSuccessful = false;
94 gl::GLContext* gl = mContext->gl;
96 static const bool kDumpShaders = PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS");
97 if (MOZ_UNLIKELY(kDumpShaders)) {
98 printf_stderr("==== begin MOZ_WEBGL_DUMP_SHADERS ====\n");
99 PrintLongString(mSource.c_str(), mSource.size());
103 const auto validator = mContext->CreateShaderValidator(mType);
104 MOZ_ASSERT(validator);
106 mCompileResults = validator->ValidateAndTranslate(mSource.c_str());
109 mCompilationLog = mCompileResults->mInfoLog.c_str();
110 const auto& success = mCompileResults->mValid;
112 if (MOZ_UNLIKELY(kDumpShaders)) {
113 printf_stderr("\n==== \\/ \\/ \\/ ====\n");
114 if (success) {
115 const auto& translated = mCompileResults->mObjectCode;
116 PrintLongString(translated.data(), translated.size());
117 } else {
118 printf_stderr("Validation failed:\n%s",
119 mCompileResults->mInfoLog.c_str());
121 printf_stderr("\n==== end ====\n");
124 if (!success) return;
126 const std::array<const char*, 1> parts = {
127 mCompileResults->mObjectCode.c_str()};
128 gl->fShaderSource(mGLName, parts.size(), parts.data(), nullptr);
130 gl->fCompileShader(mGLName);
132 GetCompilationStatusAndLog(gl, mGLName, &mCompilationSuccessful,
133 &mCompilationLog);
136 ////////////////////////////////////////////////////////////////////////////////
138 size_t WebGLShader::CalcNumSamplerUniforms() const {
139 size_t accum = 0;
140 for (const auto& cur : mCompileResults->mUniforms) {
141 const auto& type = cur.type;
142 if (type == LOCAL_GL_SAMPLER_2D || type == LOCAL_GL_SAMPLER_CUBE) {
143 accum += cur.getArraySizeProduct();
146 return accum;
149 size_t WebGLShader::NumAttributes() const {
150 return mCompileResults->mAttributes.size();
153 void WebGLShader::BindAttribLocation(GLuint prog, const std::string& userName,
154 GLuint index) const {
155 for (const auto& attrib : mCompileResults->mAttributes) {
156 if (attrib.name == userName) {
157 mContext->gl->fBindAttribLocation(prog, index, attrib.mappedName.c_str());
158 return;
163 void WebGLShader::MapTransformFeedbackVaryings(
164 const std::vector<std::string>& varyings,
165 std::vector<std::string>* out_mappedVaryings) const {
166 MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
167 MOZ_ASSERT(out_mappedVaryings);
169 out_mappedVaryings->clear();
170 out_mappedVaryings->reserve(varyings.size());
172 const auto& shaderVaryings = mCompileResults->mVaryings;
174 for (const auto& userName : varyings) {
175 const auto* mappedName = &userName;
176 for (const auto& shaderVarying : shaderVaryings) {
177 if (shaderVarying.name == userName) {
178 mappedName = &shaderVarying.mappedName;
179 break;
182 out_mappedVaryings->push_back(*mappedName);
186 ////////////////////////////////////////////////////////////////////////////////
187 // Boilerplate
189 size_t WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
190 return mallocSizeOf(this) + mSource.size() + 1 +
191 mCompileResults->SizeOfIncludingThis(mallocSizeOf) +
192 mCompilationLog.size() + 1;
195 } // namespace mozilla