2018-11-30 22:52:05 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-10-05 00:35:54 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
2012-12-03 17:10:23 +04:00
|
|
|
#include "WebGLShader.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
2018-02-24 02:47:41 +03:00
|
|
|
#include "GLSLANG/ShaderLang.h"
|
2013-09-04 16:14:52 +04:00
|
|
|
#include "GLContext.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
|
|
|
#include "mozilla/MemoryReporting.h"
|
2015-01-16 02:40:39 +03:00
|
|
|
#include "nsPrintfCString.h"
|
|
|
|
#include "nsString.h"
|
2015-11-25 07:15:29 +03:00
|
|
|
#include "prenv.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
#include "WebGLContext.h"
|
|
|
|
#include "WebGLObjectModel.h"
|
2015-01-16 02:40:39 +03:00
|
|
|
#include "WebGLShaderValidator.h"
|
|
|
|
#include "WebGLValidateStrings.h"
|
2012-10-05 00:35:54 +04:00
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
namespace mozilla {
|
2012-10-05 00:35:54 +04:00
|
|
|
|
2018-05-31 23:58:53 +03:00
|
|
|
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.
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-31 23:58:53 +03:00
|
|
|
const size_t chunkSize = 1000;
|
|
|
|
const UniqueBuffer buf(moz_xmalloc(chunkSize + 1)); // +1 for null-term
|
|
|
|
const auto bufBegin = (char*)buf.get();
|
|
|
|
bufBegin[chunkSize] = '\0';
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-31 23:58:53 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
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,
|
2020-01-09 01:19:16 +03:00
|
|
|
std::string* const out_log) {
|
2015-01-16 02:40:39 +03:00
|
|
|
GLint compileStatus = LOCAL_GL_FALSE;
|
|
|
|
gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &compileStatus);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
// It's simpler if we always get the log.
|
|
|
|
GLint lenWithNull = 0;
|
|
|
|
gl->fGetShaderiv(shader, LOCAL_GL_INFO_LOG_LENGTH, &lenWithNull);
|
2020-01-09 01:19:16 +03:00
|
|
|
if (lenWithNull < 1) {
|
|
|
|
lenWithNull = 1;
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
2020-01-09 01:19:16 +03:00
|
|
|
std::vector<char> buffer(lenWithNull);
|
|
|
|
gl->fGetShaderInfoLog(shader, buffer.size(), nullptr, buffer.data());
|
|
|
|
*out_log = buffer.data();
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
*out_success = (compileStatus == LOCAL_GL_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
|
2020-01-09 01:19:16 +03:00
|
|
|
: WebGLContextBoundObject(webgl),
|
2017-12-20 04:21:18 +03:00
|
|
|
mGLName(webgl->gl->fCreateShader(type)),
|
2019-06-21 19:52:50 +03:00
|
|
|
mType(type) {
|
|
|
|
mCompileResults = std::make_unique<webgl::ShaderValidatorResults>();
|
2012-12-03 17:10:23 +04:00
|
|
|
}
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
WebGLShader::~WebGLShader() {
|
|
|
|
if (!mContext) return;
|
|
|
|
mContext->gl->fDeleteShader(mGLName);
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2020-01-09 01:19:23 +03:00
|
|
|
void WebGLShader::ShaderSource(const std::string& cleanSource) {
|
|
|
|
const auto badChar =
|
|
|
|
CheckGLSLPreprocString(mContext->IsWebGL2(), cleanSource);
|
|
|
|
MOZ_ASSERT(!badChar);
|
|
|
|
if (badChar) return;
|
|
|
|
mSource = cleanSource;
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WebGLShader::CompileShader() {
|
|
|
|
mCompilationSuccessful = false;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
gl::GLContext* gl = mContext->gl;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-31 23:58:53 +03:00
|
|
|
static const bool kDumpShaders = PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS");
|
|
|
|
if (MOZ_UNLIKELY(kDumpShaders)) {
|
|
|
|
printf_stderr("==== begin MOZ_WEBGL_DUMP_SHADERS ====\n");
|
2020-01-09 01:19:16 +03:00
|
|
|
PrintLongString(mSource.c_str(), mSource.size());
|
2018-05-31 23:58:53 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-06-21 19:52:50 +03:00
|
|
|
{
|
|
|
|
const auto validator = mContext->CreateShaderValidator(mType);
|
|
|
|
MOZ_ASSERT(validator);
|
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
mCompileResults = validator->ValidateAndTranslate(mSource.c_str());
|
2019-06-21 19:52:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mCompilationLog = mCompileResults->mInfoLog.c_str();
|
|
|
|
const auto& success = mCompileResults->mValid;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-05-31 23:58:53 +03:00
|
|
|
if (MOZ_UNLIKELY(kDumpShaders)) {
|
|
|
|
printf_stderr("\n==== \\/ \\/ \\/ ====\n");
|
|
|
|
if (success) {
|
2019-06-21 19:52:50 +03:00
|
|
|
const auto& translated = mCompileResults->mObjectCode;
|
2020-01-09 01:19:16 +03:00
|
|
|
PrintLongString(translated.data(), translated.size());
|
2015-01-16 02:40:39 +03:00
|
|
|
} else {
|
2019-06-21 19:52:50 +03:00
|
|
|
printf_stderr("Validation failed:\n%s",
|
|
|
|
mCompileResults->mInfoLog.c_str());
|
2018-05-31 23:58:53 +03:00
|
|
|
}
|
|
|
|
printf_stderr("\n==== end ====\n");
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2018-05-31 23:58:53 +03:00
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
if (!success) return;
|
|
|
|
|
2019-06-21 19:52:50 +03:00
|
|
|
const std::array<const char*, 1> parts = {
|
|
|
|
mCompileResults->mObjectCode.c_str()};
|
|
|
|
gl->fShaderSource(mGLName, parts.size(), parts.data(), nullptr);
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
gl->fCompileShader(mGLName);
|
|
|
|
|
|
|
|
GetCompilationStatusAndLog(gl, mGLName, &mCompilationSuccessful,
|
|
|
|
&mCompilationLog);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
size_t WebGLShader::CalcNumSamplerUniforms() const {
|
2019-05-17 05:36:57 +03:00
|
|
|
size_t accum = 0;
|
2019-06-21 19:52:50 +03:00
|
|
|
for (const auto& cur : mCompileResults->mUniforms) {
|
2019-05-17 05:36:57 +03:00
|
|
|
const auto& type = cur.type;
|
|
|
|
if (type == LOCAL_GL_SAMPLER_2D || type == LOCAL_GL_SAMPLER_CUBE) {
|
|
|
|
accum += cur.getArraySizeProduct();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return accum;
|
2015-10-24 07:35:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t WebGLShader::NumAttributes() const {
|
2019-06-21 19:52:50 +03:00
|
|
|
return mCompileResults->mAttributes.size();
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
2019-05-17 05:36:57 +03:00
|
|
|
void WebGLShader::BindAttribLocation(GLuint prog, const std::string& userName,
|
2015-01-16 02:40:39 +03:00
|
|
|
GLuint index) const {
|
2019-06-21 19:52:50 +03:00
|
|
|
for (const auto& attrib : mCompileResults->mAttributes) {
|
2019-05-17 05:36:57 +03:00
|
|
|
if (attrib.name == userName) {
|
|
|
|
mContext->gl->fBindAttribLocation(prog, index, attrib.mappedName.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
void WebGLShader::MapTransformFeedbackVaryings(
|
2020-01-09 01:19:16 +03:00
|
|
|
const std::vector<std::string>& varyings,
|
2016-09-10 07:02:54 +03:00
|
|
|
std::vector<std::string>* out_mappedVaryings) const {
|
2015-04-21 04:02:34 +03:00
|
|
|
MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
|
|
|
|
MOZ_ASSERT(out_mappedVaryings);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
out_mappedVaryings->clear();
|
|
|
|
out_mappedVaryings->reserve(varyings.size());
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-06-21 19:52:50 +03:00
|
|
|
const auto& shaderVaryings = mCompileResults->mVaryings;
|
2019-05-17 05:36:57 +03:00
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
for (const auto& userName : varyings) {
|
2019-05-17 05:36:57 +03:00
|
|
|
const auto* mappedName = &userName;
|
|
|
|
for (const auto& shaderVarying : shaderVaryings) {
|
|
|
|
if (shaderVarying.name == userName) {
|
|
|
|
mappedName = &shaderVarying.mappedName;
|
|
|
|
break;
|
|
|
|
}
|
2015-04-21 04:02:34 +03:00
|
|
|
}
|
2019-05-17 05:36:57 +03:00
|
|
|
out_mappedVaryings->push_back(*mappedName);
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2015-04-21 04:02:34 +03:00
|
|
|
}
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Boilerplate
|
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
size_t WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const {
|
2020-01-09 01:19:16 +03:00
|
|
|
return mallocSizeOf(this) + mSource.size() + 1 +
|
2019-06-21 19:52:50 +03:00
|
|
|
mCompileResults->SizeOfIncludingThis(mallocSizeOf) +
|
2020-01-09 01:19:16 +03:00
|
|
|
mCompilationLog.size() + 1;
|
2012-12-03 17:10:23 +04:00
|
|
|
}
|
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
} // namespace mozilla
|