summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGLShader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/WebGLShader.cpp')
-rw-r--r--dom/canvas/WebGLShader.cpp190
1 files changed, 190 insertions, 0 deletions
diff --git a/dom/canvas/WebGLShader.cpp b/dom/canvas/WebGLShader.cpp
new file mode 100644
index 0000000000..033e97fe2b
--- /dev/null
+++ b/dom/canvas/WebGLShader.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGLShader.h"
+
+#include "GLSLANG/ShaderLang.h"
+#include "GLContext.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "mozilla/MemoryReporting.h"
+#include "nsPrintfCString.h"
+#include "nsString.h"
+#include "prenv.h"
+#include "WebGLContext.h"
+#include "WebGLObjectModel.h"
+#include "WebGLShaderValidator.h"
+#include "WebGLValidateStrings.h"
+
+namespace mozilla {
+
+static void PrintLongString(const char* const begin, const size_t len) {
+ // Wow - Roll Your Own Foreach-Lines because printf_stderr has a hard-coded
+ // internal size, so long strings are truncated.
+
+ const size_t chunkSize = 1000;
+ auto buf = std::vector<char>(chunkSize + 1); // +1 for null-term
+ const auto bufBegin = buf.data();
+
+ auto chunkBegin = begin;
+ const auto end = begin + len;
+ while (chunkBegin + chunkSize < end) {
+ memcpy(bufBegin, chunkBegin, chunkSize);
+ printf_stderr("%s", bufBegin);
+ chunkBegin += chunkSize;
+ }
+ printf_stderr("%s", chunkBegin);
+}
+
+template <size_t N>
+static bool SubstringStartsWith(const std::string& testStr, size_t offset,
+ const char (&refStr)[N]) {
+ for (size_t i = 0; i < N - 1; i++) {
+ if (testStr[offset + i] != refStr[i]) return false;
+ }
+ return true;
+}
+
+static void GetCompilationStatusAndLog(gl::GLContext* gl, GLuint shader,
+ bool* const out_success,
+ std::string* const out_log) {
+ GLint compileStatus = LOCAL_GL_FALSE;
+ gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &compileStatus);
+
+ // It's simpler if we always get the log.
+ GLint lenWithNull = 0;
+ gl->fGetShaderiv(shader, LOCAL_GL_INFO_LOG_LENGTH, &lenWithNull);
+ if (lenWithNull < 1) {
+ lenWithNull = 1;
+ }
+ std::vector<char> buffer(lenWithNull);
+ gl->fGetShaderInfoLog(shader, buffer.size(), nullptr, buffer.data());
+ *out_log = buffer.data();
+
+ *out_success = (compileStatus == LOCAL_GL_TRUE);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
+ : WebGLContextBoundObject(webgl),
+ mGLName(webgl->gl->fCreateShader(type)),
+ mType(type) {
+ mCompileResults = std::make_unique<webgl::ShaderValidatorResults>();
+}
+
+WebGLShader::~WebGLShader() {
+ if (!mContext) return;
+ mContext->gl->fDeleteShader(mGLName);
+}
+
+void WebGLShader::ShaderSource(const std::string& u8) {
+ mSource = CrushGlslToAscii(u8);
+}
+
+void WebGLShader::CompileShader() {
+ mCompilationSuccessful = false;
+
+ gl::GLContext* gl = mContext->gl;
+
+ static const bool kDumpShaders = PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS");
+ if (MOZ_UNLIKELY(kDumpShaders)) {
+ printf_stderr("==== begin MOZ_WEBGL_DUMP_SHADERS ====\n");
+ PrintLongString(mSource.c_str(), mSource.size());
+ }
+
+ {
+ const auto validator = mContext->CreateShaderValidator(mType);
+ MOZ_ASSERT(validator);
+
+ mCompileResults = validator->ValidateAndTranslate(mSource.c_str());
+ }
+
+ mCompilationLog = mCompileResults->mInfoLog.c_str();
+ const auto& success = mCompileResults->mValid;
+
+ if (MOZ_UNLIKELY(kDumpShaders)) {
+ printf_stderr("\n==== \\/ \\/ \\/ ====\n");
+ if (success) {
+ const auto& translated = mCompileResults->mObjectCode;
+ PrintLongString(translated.data(), translated.size());
+ } else {
+ printf_stderr("Validation failed:\n%s",
+ mCompileResults->mInfoLog.c_str());
+ }
+ printf_stderr("\n==== end ====\n");
+ }
+
+ if (!success) return;
+
+ const std::array<const char*, 1> parts = {
+ mCompileResults->mObjectCode.c_str()};
+ gl->fShaderSource(mGLName, parts.size(), parts.data(), nullptr);
+
+ gl->fCompileShader(mGLName);
+
+ GetCompilationStatusAndLog(gl, mGLName, &mCompilationSuccessful,
+ &mCompilationLog);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+size_t WebGLShader::CalcNumSamplerUniforms() const {
+ size_t accum = 0;
+ for (const auto& cur : mCompileResults->mUniforms) {
+ const auto& type = cur.type;
+ if (type == LOCAL_GL_SAMPLER_2D || type == LOCAL_GL_SAMPLER_CUBE) {
+ accum += cur.getArraySizeProduct();
+ }
+ }
+ return accum;
+}
+
+size_t WebGLShader::NumAttributes() const {
+ return mCompileResults->mAttributes.size();
+}
+
+void WebGLShader::BindAttribLocation(GLuint prog, const std::string& userName,
+ GLuint index) const {
+ for (const auto& attrib : mCompileResults->mAttributes) {
+ if (attrib.name == userName) {
+ mContext->gl->fBindAttribLocation(prog, index, attrib.mappedName.c_str());
+ return;
+ }
+ }
+}
+
+void WebGLShader::MapTransformFeedbackVaryings(
+ const std::vector<std::string>& varyings,
+ std::vector<std::string>* out_mappedVaryings) const {
+ MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
+ MOZ_ASSERT(out_mappedVaryings);
+
+ out_mappedVaryings->clear();
+ out_mappedVaryings->reserve(varyings.size());
+
+ const auto& shaderVaryings = mCompileResults->mVaryings;
+
+ for (const auto& userName : varyings) {
+ const auto* mappedName = &userName;
+ for (const auto& shaderVarying : shaderVaryings) {
+ if (shaderVarying.name == userName) {
+ mappedName = &shaderVarying.mappedName;
+ break;
+ }
+ }
+ out_mappedVaryings->push_back(*mappedName);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Boilerplate
+
+size_t WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
+ return mallocSizeOf(this) + mSource.size() + 1 +
+ mCompileResults->SizeOfIncludingThis(mallocSizeOf) +
+ mCompilationLog.size() + 1;
+}
+
+} // namespace mozilla