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"
10 #include "mozilla/dom/WebGLRenderingContextBinding.h"
11 #include "mozilla/MemoryReporting.h"
12 #include "nsPrintfCString.h"
15 #include "WebGLContext.h"
16 #include "WebGLObjectModel.h"
17 #include "WebGLShaderValidator.h"
18 #include "WebGLValidateStrings.h"
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 auto buf
= std::vector
<char>(chunkSize
+ 1); // +1 for null-term
28 const auto bufBegin
= buf
.data();
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
;
37 printf_stderr("%s", chunkBegin
);
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;
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
);
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) {
61 std::vector
<char> buffer(lenWithNull
);
62 gl
->fGetShaderInfoLog(shader
, buffer
.size(), nullptr, buffer
.data());
63 *out_log
= buffer
.data();
65 *out_success
= (compileStatus
== LOCAL_GL_TRUE
);
68 ////////////////////////////////////////////////////////////////////////////////
70 WebGLShader::WebGLShader(WebGLContext
* webgl
, GLenum type
)
71 : WebGLContextBoundObject(webgl
),
72 mGLName(webgl
->gl
->fCreateShader(type
)),
74 mCompileResults
= std::make_unique
<webgl::ShaderValidatorResults
>();
77 WebGLShader::~WebGLShader() {
78 if (!mContext
) return;
79 mContext
->gl
->fDeleteShader(mGLName
);
82 void WebGLShader::ShaderSource(const std::string
& u8
) {
83 mSource
= CrushGlslToAscii(u8
);
86 void WebGLShader::CompileShader() {
87 mCompilationSuccessful
= false;
89 gl::GLContext
* gl
= mContext
->gl
;
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());
98 const auto validator
= mContext
->CreateShaderValidator(mType
);
99 MOZ_ASSERT(validator
);
101 mCompileResults
= validator
->ValidateAndTranslate(mSource
.c_str());
104 mCompilationLog
= mCompileResults
->mInfoLog
.c_str();
105 const auto& success
= mCompileResults
->mValid
;
107 if (MOZ_UNLIKELY(kDumpShaders
)) {
108 printf_stderr("\n==== \\/ \\/ \\/ ====\n");
110 const auto& translated
= mCompileResults
->mObjectCode
;
111 PrintLongString(translated
.data(), translated
.size());
113 printf_stderr("Validation failed:\n%s",
114 mCompileResults
->mInfoLog
.c_str());
116 printf_stderr("\n==== end ====\n");
119 if (!success
) return;
121 const std::array
<const char*, 1> parts
= {
122 mCompileResults
->mObjectCode
.c_str()};
123 gl
->fShaderSource(mGLName
, parts
.size(), parts
.data(), nullptr);
125 gl
->fCompileShader(mGLName
);
127 GetCompilationStatusAndLog(gl
, mGLName
, &mCompilationSuccessful
,
131 ////////////////////////////////////////////////////////////////////////////////
133 size_t WebGLShader::CalcNumSamplerUniforms() const {
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();
144 size_t WebGLShader::NumAttributes() const {
145 return mCompileResults
->mAttributes
.size();
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());
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
);
164 out_mappedVaryings
->clear();
165 out_mappedVaryings
->reserve(varyings
.size());
167 const auto& shaderVaryings
= mCompileResults
->mVaryings
;
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
;
177 out_mappedVaryings
->push_back(*mappedName
);
181 ////////////////////////////////////////////////////////////////////////////////
184 size_t WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf
) const {
185 return mallocSizeOf(this) + mSource
.size() + 1 +
186 mCompileResults
->SizeOfIncludingThis(mallocSizeOf
) +
187 mCompilationLog
.size() + 1;
190 } // namespace mozilla