gecko-dev/dom/canvas/WebGLShader.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

196 строки
6.0 KiB
C++
Исходник Обычный вид История

/* -*- 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;
const UniqueBuffer buf(moz_xmalloc(chunkSize + 1)); // +1 for null-term
const auto bufBegin = (char*)buf.get();
bufBegin[chunkSize] = '\0';
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);
}
Bug 1477756 - Fix all webgl regression tests according to CI. r=handyman (This is a combination of 31 commits) * Fix Linux compilation. * Fix mac compilation. * CI compile fixes. * printf's size_t is %zu. %tu would be unsigned ptrdiff_t. * No non-ref Maybe args. * MOZ_CRASH for noreturn * Handle implied texture sizes, rewrite comment stripping. * Replace e.g. WebGLProgramInner with simpler webgl::ProgramKeepAlive. * Bounce ValidateProgram call off driver. * Uniform name length limit, cubemap fb-attach, non-array uniforms, undersized texImage views. * alignas for uint8_t[sizeof(float)*N] pun buffers. * CC fixes? * Fill attrib0Active. * Repair max-warnings limit. * This is basically required in order for CI's logging to not explode. * Don't cache WebGLMemoryTracker. * Deleted prog/shader error, no texSubImage(null), client-side fingerprint resist for exts. * Fix GetUniformIndices and MakeRangeFromView. * CC Traverse base class from within derived class to fix leaking the world. :( * PauseTransformFeedback * TexImage video fastpath * GetFragLocation for arrays * Forbid BindBufferRange during TF * Mark tests and fix RBAB query and test. * Change(!) query deletion behavior to match spec. * Mark conformance2/query/query.html failing for now. * Implicitly EndQuery on DeleteQuery while spec is in flux. * Fix error code for test. * RAII LruPosition for WebGL context limit. * Include std::list. * Mark CompileResult and LinkResult.pending as false when retrieved. * Hold strong-ref to NotLostData during Run<> to prevent LoseContext=>UAF. * Don't assume GetUniformLocation(foo+'[0]') means foo is an array. * Don't assume !mCanvasElement means !!mOffscreenCanvas. * Handle composition while context-lost. * All non-value-init members must be const or have inline init. * Mark passing tests on Linux. Depends on D54019 Differential Revision: https://phabricator.services.mozilla.com/D55739 --HG-- extra : moz-landing-system : lando
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;
}
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