Files
palemoon27/dom/canvas/WebGLProgram.cpp
T
roytam1 7f8ba9c1d7 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1236786 - [WebGL2] pass getVertexAttrib in gl-object-get-calls.html, r=jgilbert (60a2c91a38)
- Bug 1233046 - Fix OES_texture_float on OSX. - r=jrmuizel (4bc0059f5f)
- Bug 1233557 - Allow RGB8 to be renderable again for web-compat. - r=jrmuizel (4c13bfd8e8)
- Bug 1233549. Disallow ES3 compressed texture formats. r=jgilbert (1073033161)
- Bug 1241702 - Allow unsized DEPTH_STENCIL for RBs in WebGL 2. - r=kamidphish (87d17d2cf9)
- Bug 1239126. Handle gl_InstanceID attribute with no location. r=jgilbert (4894997e98)
- Bug 1236782 - [WebGL2] pass getProgramParameter in gl-object-get-calls.html; r=jgilbert (2136fcce48)
- Bug 1232462. Only ask for a higher version of GLSL when using WebGL2. r=jgilbert (0317be4eb4)
- Bug 1242330 - "Four extensions were promoted to core in WebGL 2 and should no longer be available as extensions." r=jgilbert r=jmuizelaar (6df020b8d4)
- Bug 1233626 - Default MaxDrawingBuffers to 1 unless ext/webgl2. - r=jrmuizel (a7580d661c)
- Bug 1231657. Don't allow linking different versions shaders. r=jgilbert (e610f98066)
- Bug 1241777 - TexCompareFunc should be stored in ascending order. r=jgilbert (b6151a0076)
- Bug 1228885 - Implement WebGLTexture::MemoryUsage. - r=kamidphish (ea06815414)
- Bug 1239259 - Fix WebGL2 generateMipmap checking. r=jgilbert (39f587c421)
- Bug 1242347 - Allow unsized internal format when generate mipmap. r=jgilbert (b203a8898c)
- Bug 1232502. Use the correct internalFormat when calling CopyTexImage2D. r=jgilbert (eeaef3215e)
- Bug 1243663 - Max uniform and attribute location lengths in WebGL2 should be 1024. r=jgilbert (c4ec6de507)
- Bug 1239488 - Add int/uint to vertex attrib data type. r=jgilbert (11b4968025)
- Bug 1184242 - Remove aTabParent != sActiveTabParent warning from IMEStateManager::SetInputContextForChildProcess. r=masayuki (0fcda10e15)
- Bug 1178652 - Send NOTIFY_IME_OF_COMPOSITION_UPDATE to parent process correctly. r=masayuki (bce28e2c91)
- Bug 1107782 - Only accept certain mouse, gamepad events as user-active. r=smaug (00542c80b9)
- Bug 1247850 - Shrink NameTableKey in nsStaticCaseInsensitiveNameTable. r=froydnj,erahm. (ce3cb3edfb)
- Bug 1247359 - micro-optimize the common case of String{Begins,End}With; r=erahm (333e042b31)
- Bug 1239125. Add operator!=(char_type*) to nsTSubstring. r=froydnj (0cc047a9a1)
- Bug 1213862 - Align nsString whitespace handling with web specs; r=froydnj (db5b11ca52)
- Bug 1141884 - Trigger compositor smooth scrolling to snap points when APZ is enabled. r=mstange,kip (593af59f2a)
- Bug 1244582: Add back in a null check that was accidentally removed. r=smaug (76bff1b01f)
- Bug 1234176 - Introduce and use the WriteSysFile() helper function. r=dhylands (22a46fbe8b)
- missing bit of Bug 1198124 - Enable -Wshadow (f84535a7a2)
- Bug 1249171 - Simplify nsCOMArray::SizeOfExcludingThis(). r=erahm. (57efdce1c6)
- Bug 1156416 - Validate camera parameters supplied by the application. r=mikeh (f8b4b84ccf)
- Bug 1186808 - Replace nsBaseHashtable::EnumerateRead() calls in dom/camera/ with iterators. r=mikeh. (7b1db5f6a1)
- Bug 1158378 - Fix how a failed set configuration call would try to shutdown the camera after release. (9d5e323bca)
- Bug 1171374 - Permit software video codecs with the emulated camera. r=sotaro (c1ae26ea0d)
- Bug 1234458 P1 Allow the CacheChild to be "locked" into memory so it will delay destruction. r=ehsan a=ritu (9e46185779)
- Bug 1234458 P2 Lock the CacheChild actor while Cache DOM methods are running. r=ehsan a=ritu (038342a6e2)
- Bug 1244764 P1 Make Cache .add()/.addAll() fail if a Response.ok() is false. r=ehsan (ae26ca9ef1)
- Bug 1172562 - Clear QuotaManager storage when uninstalling an app. Test. r=bkelly (b07311a3b7)
- Bug 1172629 - Use the caches global property from an iframe loaded after setting the pref in order to make the tests pass with the pref disabled; r=bkelly a=RyanVM (e7c05d8b79)
- Bug 1244764 P2 Make dom/cache mochitests pass with new add()/addAll() behavior. r=ehsan (e1f667c1b4)
- Bug 1244764 P3 Make service worker tests pass with new Cache add()/addAll() behavior. r=ehsan (1518ae5225)
- Bug 1003860 - Simplify storage setup tasks in storage inspector tests. r=mratcliffe (249a8bdb2b)
- Bug 1003860 - Service worker cache for storage actor. r=mratcliffe (5c3d1ecd0c)
- Bug 1244764 P5 Fix devtools test to work with new Cache add()/addAll() behavior. r=ehsan (bf85405de8)
- Bug 1232901 - Use channel.asyncOpen2 within dom/browser-element/BrowserElementParent.js (r=sicking,aus) (2a228ed551)
- Bug 1180330 - http auth prompt shown when opening browser if prompt canceled/dismissed earlier. r=fabrice (ba3666f4bd)
- Bug 1234118 - Delete code for supporting 'do-command' and 'copypaste-docommand'. r=mtseng, r=smaug (b1b575d3c5)
- Bug 1238883 - [TV Browser] It shows "The page cannot be displayed" when user browse some webpages. r=roc (e6d7739dd6)
- Bug 1238440 - FileReader should throw an error when the blob changed size when reading, r=khuey (b006adba10)
- Bug 1230422 - FileReader should handle nested ReadAs*() calls. r=khuey (5a3ff84a31)
- Bug 1225202, part 3 - Create files in test_fileapi_slice.html using SpecialPowers.createFiles. r=baku (1137975548)
- Bug 1241171 - FormData should not force 'blob' as filename, r=smaug (748055f751)
- Bug 1246375 - Restore the previous spec version of FormData, r=smaug (3586af2b88)
- Bug 1237183 - Modify implementation of reading preference. r=seanlin (a132bc7246)
- Bug 801545 - Remove DocumentType.internalSubset, r=bz (ea30c9b5ee)
- Bug 1226440 - Expose a method to get a node's immediate dominator; r=bz,sfink (f77ae44037)
- Bug 825318 - Implement adoptDownload for mozDownloadManager, r=aus, r=sicking (e98cb05210)
- Bug 1237370 - Always log the reason for remote AppRep lookup failures. r=gcp (2c804e68fc)
- Bug 1167493 - Application Reputation: disable remote lookup of zip files on Mac/Linux, r=gcp (517459e064)
- Bug 1195519 - Use channel->ascynOpen2 toolkit/components/downloads/ApplicationReputation.cpp (r=sicking) (2856e5213a)
- Bug 1237856 - Add prefs to honor/ignore Application Reputation verdicts. r=gcp (54ee06264f)
- Bug 1243643 - Deprecate unsafe CPOW usage in contentAreaUtils' saveImage. r=jld (6ae790f1ef)
- Bug 1229224: Add an eslint plugin for importing all browser.js globals for browser-chrome tests. r=miker (9df52a7f3b)
- Bug 1245916: Add additional browser window scripts to eslint globals. r=felipe (92d316ca5e)
- Bug 1246244 - Allow non-CPOW documents to pass through saveImageURL properly. r=jaws,Margaret (c8d4ca241d)
- some missing bits after world fix (c0439eebb0)
- add some missing stuff (ddbd47dc03)
- bissing bit of 1229519 (4e255c3dae)
- Bug 1199662 - Crash ping environment block is broken when any string field contains a quotation mark. Unescape INI fields properly using the library that already exists for the purpose. r=ted (874a999edc)
- Bug 1216150 - Turn on the experimental Intl.DateTimeFormat.prototype.formatToParts in b2g certified apps. r=fabrice (40eeb1a4d4)
- Bug 1216150 - Mini-bustage fix for something I think I unintentionally qref'd into the final patch. r=bustage in a CLOSED TREE (36d9b21a67)
- Bug 1141311 - Add async mode support to GonkNativeWindow on Lollipop Gonk r=pchang (39d9d56326)
- Bug 1146671 - Ensure camera not already released when performing operations. r=dhylands (71b59caa1f)
- Bug 1248737. Improve documentation for WorkerRunnable and associated classes. r=khuey (4ff57790c5)
- Bug 1235629 - Remove dead code in WorkerFeature.h, r=smaug (75a51fcf03)
- Bug 1212333 - WorkerDebuggerManager should live on the main thread;r=khuey (11fdfbbae6)
- Bug 1226443 P3 Re-enable service worker update wpt tests. r=ehsan (605dac5f9e)
- Bug 1226443 P4 Cleanup ServiceWorkerScriptCache objects when initialization fails. r=ehsan (43de3429a2)
- Bug 1234127: Change |BluetoothAdapter.pairingReqs| as a nullable object; r=btian, r=mrbkap (45d2038f6a)
- Bug 1188487 - BrowserElement webidl changes for muting and setting volume. r=ehsan (21bea70a07)
- Bug 1238210 - Correct the Promise return types on two Clients methods; r=baku (fa41b25df0)
- Bug 1246784 - Expose Console to the WorkerDebuggerGlobalScope - part 2, r=khuey (0da9ce8ff6)
- Bug 1228702. Don't expose the 'location' property of Exception/DOMException on workers. r=bholley (0fe86ea586)
- Bug 1223825 - Change Directory.path to include the directory's name. r=baku (0cdae4c2f0)
- Bug 1238225 - Mark ExtendableMessageEvent.ports as SameObject; r=baku (45b9a9746f)
- Bug 1236933 - Return null from FetchEvent.clientId for non-subresource network requests; r=bkelly (4a9c4b40cb)
- Bug 1238213 - Make FetchEvent.request non-nullable; r=baku (751082c8ba)
- Bug 1193125 - Avoid corrupting image data in test_fetch_event.html. r=bkelly (9f6bff232f)
- Bug 1201664 - Avoid using Request's constructor when creating FetchEvent.request; r=bkelly (7a3401e345)
- Bug 1175944 - Packaged app's (app://) JS files are not loaded and do not trigger "onfetch" handler. r=jdm (62df139153)
- Bug 1233644 - use pattern matching when listening clear-origin-data. r=baku (ea2594f50e)
- Bug 1237363 - Part 1: Unregister all service workers registered in mochitests at the end of the test; r=jdm (5be97e5bb0)
- Bug 1237363 - Part 2: Fail mochitests which register a service worker without unregistering it; r=jdm (c4160ffd5f)
- Bug 1237363 - Part 3: Add a test for a mochitest finishing without unregistering its service worker; r=jdm (911d37291b)
- Bug 1174078 - Calling "fetch" inside Service Worker's "onfetch" handler in b2g causes "onfetch" again that leads to an infinite loop. Test. r=nsm (208451f346)
- Bug 1197379 - Remove support for intercepting app:// URIs using service workers; r=jdm (3cbdd725f1)
- Bug 1179399 - Part 1: Relax the ShouldIntercept checks when overriding JAR channel info; r=jdm (850bb2bdb8)
- Bug 1238213 follow-up: Mark the FetchEventInit dictionary argument to FetchEvent's constructor optional too; r=bzbarsky (356cbe6db7)
- Bug 1232732 - modify NS_WARNING in MOZ_WIN_MEM_TRY_CATCH; r=aklotz (e2be4d6919)
- Bug 1247658 - Expose a method to JS for find the shortest retaining paths of some nodes in a heap snapshot; r=bz r=jimb (2c82198808)
- Bug 1188115: Expose IDBCursorWithValue in workers. r=baku (e1c40aeb6e)
- Bug 1162680 - Notify Keyboard.jsm to send blur event when the message manager is closed first. r=timdream (53727ab300)
- Bug 1192986 Also mark Cache/CacheStorage as release interfaces on workers. r=ehsan a=bustage (25cf83c154)
- Bug 1159742. Get rid of the pref annotation from test_interfaces, since it basically corresponds to disabling the test. r=jst (c229e3f881)
- Bug 1203160 - Part 2: Fix the interfaces tests to allow SW interfaces for non-release Fennec; r=baku (072840db1f)
- Bug 1197700 - Correct mistakes in InputMethod.webidl. r=kanru, r=janjongboom, sr=smaug (4edb6f201f)
- Bug 1206970 - Stop expecting AnimationPlaybackEvent to be exposed on release branches, where it's disabled by pref, r=smaug (30ae2b13db)
- Bug 1177276 - Pref on canvas.captureStream by default. r=smaug,mt (0cfe0f72f2)
- Bug 1215147 - Enable VR API's on FF for Android by default. r=snorp, r=vlad, r=bz (5ff3725318)
- Bug 1218482 - Enable WebVR By Default,r=bz (f26111ed82)
- Bug 1159755. Stop forcing the media.eme.apiVisible preference to be true in our test harness. r=cpearce (09f7887917)
- Bug 1149312 - Obtain test coverage for the file-backed case of MediaRecorder. r=roc (bd2e7e40f0)
- Bug 1154559 - Remove flaky timeouts from manifest.js and register SimpleTest.registerCleanupFunction() to report unfinished tests. r=cpearce. (eb68db0fb2)
- Bug 1154564 - Add the ability to notify timeouts to MediaTestManager and remove flaky timeouts from test_playback.html. r=cpearce. (c89b4e58d9)
- Bug 1135170 - Fix up racey test_seek-1.html. rpending=mattwoodrow (b3a7d0dcd6)
- Bug 902686 - Change manifest.js to use SpecialPowers.pushPrefEnv. r=edwin (636b0edc1a)
- Bug 1183502 - give androidVersion a correct value in manifest.js. r=sotaro. (933e9ea712)
- Bug 1235588 - add null check to SimpleTest. r=bechen. (958ede68de)
- misspatch (c8922447ff)
- Bug 1151740 - pass the callback object as-is to SpecialPowers.exactGC(). r=edwin (99ca873bce)
- Bug 1197682 - InputMethodManager#setSupportsSwitchingTypes, r=janjongboom, sr=smaug (e7eb54e491)
- Bug 1201407 - Add input-manage-only events for InputMethod API. r=janjongboom, sr=smaug (776d064bd1)
- Bug 1234459 - Expose full text in the input box to InputMethod API, r=masayuki, sr=smaug (4fa0554356)
- Bug 1198163 - Workaround Mochitest app and assign frame proper permissions, r=kanru (c3bcf8ecc1)
- Bug 990250 - Fold nsIStyleSheet into CSSStyleSheet. r=dbaron (23579cb300)
2024-01-16 11:25:53 +08:00

1176 lines
39 KiB
C++

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "WebGLProgram.h"
#include "GLContext.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/RefPtr.h"
#include "WebGLActiveInfo.h"
#include "WebGLContext.h"
#include "WebGLShader.h"
#include "WebGLUniformLocation.h"
#include "WebGLValidateStrings.h"
namespace mozilla {
/* If `name`: "foo[3]"
* Then returns true, with
* `out_baseName`: "foo"
* `out_isArray`: true
* `out_index`: 3
*
* If `name`: "foo"
* Then returns true, with
* `out_baseName`: "foo"
* `out_isArray`: false
* `out_index`: <not written>
*/
static bool
ParseName(const nsCString& name, nsCString* const out_baseName,
bool* const out_isArray, size_t* const out_arrayIndex)
{
int32_t indexEnd = name.RFind("]");
if (indexEnd == -1 ||
(uint32_t)indexEnd != name.Length() - 1)
{
*out_baseName = name;
*out_isArray = false;
return true;
}
int32_t indexOpenBracket = name.RFind("[");
if (indexOpenBracket == -1)
return false;
uint32_t indexStart = indexOpenBracket + 1;
uint32_t indexLen = indexEnd - indexStart;
if (indexLen == 0)
return false;
const nsAutoCString indexStr(Substring(name, indexStart, indexLen));
nsresult errorcode;
int32_t indexNum = indexStr.ToInteger(&errorcode);
if (NS_FAILED(errorcode))
return false;
if (indexNum < 0)
return false;
*out_baseName = StringHead(name, indexOpenBracket);
*out_isArray = true;
*out_arrayIndex = indexNum;
return true;
}
static void
AddActiveInfo(WebGLContext* webgl, GLint elemCount, GLenum elemType, bool isArray,
const nsACString& baseUserName, const nsACString& baseMappedName,
std::vector<RefPtr<WebGLActiveInfo>>* activeInfoList,
std::map<nsCString, const WebGLActiveInfo*>* infoLocMap)
{
RefPtr<WebGLActiveInfo> info = new WebGLActiveInfo(webgl, elemCount, elemType,
isArray, baseUserName,
baseMappedName);
activeInfoList->push_back(info);
infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
}
static void
AddActiveBlockInfo(const nsACString& baseUserName,
const nsACString& baseMappedName,
std::vector<RefPtr<webgl::UniformBlockInfo>>* activeInfoList)
{
RefPtr<webgl::UniformBlockInfo> info = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
activeInfoList->push_back(info);
}
//#define DUMP_SHADERVAR_MAPPINGS
static already_AddRefed<const webgl::LinkedProgramInfo>
QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
{
RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
GLuint maxAttribLenWithNull = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
(GLint*)&maxAttribLenWithNull);
if (maxAttribLenWithNull < 1)
maxAttribLenWithNull = 1;
GLuint maxUniformLenWithNull = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH,
(GLint*)&maxUniformLenWithNull);
if (maxUniformLenWithNull < 1)
maxUniformLenWithNull = 1;
GLuint maxUniformBlockLenWithNull = 0;
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
(GLint*)&maxUniformBlockLenWithNull);
if (maxUniformBlockLenWithNull < 1)
maxUniformBlockLenWithNull = 1;
}
GLuint maxTransformFeedbackVaryingLenWithNull = 0;
if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH,
(GLint*)&maxTransformFeedbackVaryingLenWithNull);
if (maxTransformFeedbackVaryingLenWithNull < 1)
maxTransformFeedbackVaryingLenWithNull = 1;
}
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull);
printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull);
printf_stderr("maxUniformBlockLenWithNull: %d\n", maxUniformBlockLenWithNull);
#endif
// Attribs
GLuint numActiveAttribs = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES,
(GLint*)&numActiveAttribs);
for (GLuint i = 0; i < numActiveAttribs; i++) {
nsAutoCString mappedName;
mappedName.SetLength(maxAttribLenWithNull - 1);
GLsizei lengthWithoutNull = 0;
GLint elemCount = 0; // `size`
GLenum elemType = 0; // `type`
gl->fGetActiveAttrib(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
&elemCount, &elemType, mappedName.BeginWriting());
mappedName.SetLength(lengthWithoutNull);
// Collect ActiveInfos:
// Attribs can't be arrays, so we can skip some of the mess we have in the Uniform
// path.
nsDependentCString userName;
if (!prog->FindAttribUserNameByMappedName(mappedName, &userName))
userName.Rebind(mappedName, 0);
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[attrib %i] %s/%s\n", i, mappedName.BeginReading(),
userName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
#endif
const bool isArray = false;
AddActiveInfo(prog->mContext, elemCount, elemType, isArray, userName, mappedName,
&info->activeAttribs, &info->attribMap);
// Collect active locations:
GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
if (loc == -1) {
if (mappedName != "gl_InstanceID")
MOZ_CRASH("Active attrib has no location.");
} else {
info->activeAttribLocs.insert(loc);
}
}
// Uniforms
const bool needsCheckForArrays = gl->WorkAroundDriverBugs();
GLuint numActiveUniforms = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORMS,
(GLint*)&numActiveUniforms);
for (GLuint i = 0; i < numActiveUniforms; i++) {
nsAutoCString mappedName;
mappedName.SetLength(maxUniformLenWithNull - 1);
GLsizei lengthWithoutNull = 0;
GLint elemCount = 0; // `size`
GLenum elemType = 0; // `type`
gl->fGetActiveUniform(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
&elemCount, &elemType, mappedName.BeginWriting());
mappedName.SetLength(lengthWithoutNull);
nsAutoCString baseMappedName;
bool isArray;
size_t arrayIndex;
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
MOZ_CRASH("Failed to parse `mappedName` received from driver.");
// Note that for good drivers, `isArray` should already be correct.
// However, if FindUniform succeeds, it will be validator-guaranteed correct.
nsAutoCString baseUserName;
if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
baseUserName = baseMappedName;
if (needsCheckForArrays && !isArray) {
// By GLES 3, GetUniformLocation("foo[0]") should return -1 if `foo` is
// not an array. Our current linux Try slaves return the location of `foo`
// anyways, though.
std::string mappedNameStr = baseMappedName.BeginReading();
mappedNameStr += "[0]";
GLint loc = gl->fGetUniformLocation(prog->mGLName, mappedNameStr.c_str());
if (loc != -1)
isArray = true;
}
}
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
(int)isArray, baseMappedName.BeginReading(),
baseUserName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
printf_stderr(" isArray: %d\n", (int)isArray);
#endif
AddActiveInfo(prog->mContext, elemCount, elemType, isArray, baseUserName,
baseMappedName, &info->activeUniforms, &info->uniformMap);
}
// Uniform Blocks
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
GLuint numActiveUniformBlocks = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCKS,
(GLint*)&numActiveUniformBlocks);
for (GLuint i = 0; i < numActiveUniformBlocks; i++) {
nsAutoCString mappedName;
mappedName.SetLength(maxUniformBlockLenWithNull - 1);
GLint lengthWithoutNull;
gl->fGetActiveUniformBlockiv(prog->mGLName, i, LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH, &lengthWithoutNull);
gl->fGetActiveUniformBlockName(prog->mGLName, i, maxUniformBlockLenWithNull, &lengthWithoutNull, mappedName.BeginWriting());
mappedName.SetLength(lengthWithoutNull);
nsAutoCString baseMappedName;
bool isArray;
size_t arrayIndex;
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
MOZ_CRASH("Failed to parse `mappedName` received from driver.");
nsAutoCString baseUserName;
if (!prog->FindUniformBlockByMappedName(baseMappedName, &baseUserName,
&isArray))
{
baseUserName = baseMappedName;
if (needsCheckForArrays && !isArray) {
std::string mappedNameStr = baseMappedName.BeginReading();
mappedNameStr += "[0]";
GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName,
mappedNameStr.c_str());
if (loc != LOCAL_GL_INVALID_INDEX)
isArray = true;
}
}
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
(int)isArray, baseMappedName.BeginReading(),
baseUserName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
printf_stderr(" isArray: %d\n", (int)isArray);
#endif
AddActiveBlockInfo(baseUserName, baseMappedName, &info->uniformBlocks);
}
}
// Transform feedback varyings
if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
GLuint numTransformFeedbackVaryings = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS,
(GLint*)&numTransformFeedbackVaryings);
for (GLuint i = 0; i < numTransformFeedbackVaryings; i++) {
nsAutoCString mappedName;
mappedName.SetLength(maxTransformFeedbackVaryingLenWithNull - 1);
GLint lengthWithoutNull;
GLsizei size;
GLenum type;
gl->fGetTransformFeedbackVarying(prog->mGLName, i, maxTransformFeedbackVaryingLenWithNull,
&lengthWithoutNull, &size, &type,
mappedName.BeginWriting());
mappedName.SetLength(lengthWithoutNull);
nsAutoCString baseMappedName;
bool isArray;
size_t arrayIndex;
if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
MOZ_CRASH("Failed to parse `mappedName` received from driver.");
nsAutoCString baseUserName;
if (!prog->FindVaryingByMappedName(mappedName, &baseUserName, &isArray)) {
baseUserName = baseMappedName;
if (needsCheckForArrays && !isArray) {
std::string mappedNameStr = baseMappedName.BeginReading();
mappedNameStr += "[0]";
GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName,
mappedNameStr.c_str());
if (loc != LOCAL_GL_INVALID_INDEX)
isArray = true;
}
}
AddActiveInfo(prog->mContext, size, type, isArray, baseUserName, mappedName,
&info->transformFeedbackVaryings,
&info->transformFeedbackVaryingsMap);
}
}
return info.forget();
}
////////////////////////////////////////////////////////////////////////////////
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
: prog(prog)
, fragDataMap(nullptr)
{ }
////////////////////////////////////////////////////////////////////////////////
// WebGLProgram
static GLuint
CreateProgram(gl::GLContext* gl)
{
gl->MakeCurrent();
return gl->fCreateProgram();
}
WebGLProgram::WebGLProgram(WebGLContext* webgl)
: WebGLContextBoundObject(webgl)
, mGLName(CreateProgram(webgl->GL()))
, mTransformFeedbackBufferMode(LOCAL_GL_NONE)
{
mContext->mPrograms.insertBack(this);
}
WebGLProgram::~WebGLProgram()
{
DeleteOnce();
}
void
WebGLProgram::Delete()
{
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
gl->fDeleteProgram(mGLName);
mVertShader = nullptr;
mFragShader = nullptr;
mMostRecentLinkInfo = nullptr;
LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
}
////////////////////////////////////////////////////////////////////////////////
// GL funcs
void
WebGLProgram::AttachShader(WebGLShader* shader)
{
WebGLRefPtr<WebGLShader>* shaderSlot;
switch (shader->mType) {
case LOCAL_GL_VERTEX_SHADER:
shaderSlot = &mVertShader;
break;
case LOCAL_GL_FRAGMENT_SHADER:
shaderSlot = &mFragShader;
break;
default:
mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
return;
}
if (*shaderSlot) {
if (shader == *shaderSlot) {
mContext->ErrorInvalidOperation("attachShader: `shader` is already attached.");
} else {
mContext->ErrorInvalidOperation("attachShader: Only one of each type of"
" shader may be attached to a program.");
}
return;
}
*shaderSlot = shader;
mContext->MakeContextCurrent();
mContext->gl->fAttachShader(mGLName, shader->mGLName);
}
void
WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
{
if (!ValidateGLSLVariableName(name, mContext, "bindAttribLocation"))
return;
if (loc >= mContext->MaxVertexAttribs()) {
mContext->ErrorInvalidValue("bindAttribLocation: `location` must be less than"
" MAX_VERTEX_ATTRIBS.");
return;
}
if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) {
mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a"
" name that starts with 'gl_'.");
return;
}
NS_LossyConvertUTF16toASCII asciiName(name);
auto res = mBoundAttribLocs.insert(std::pair<nsCString, GLuint>(asciiName, loc));
const bool wasInserted = res.second;
if (!wasInserted) {
auto itr = res.first;
itr->second = loc;
}
}
void
WebGLProgram::DetachShader(WebGLShader* shader)
{
MOZ_ASSERT(shader);
WebGLRefPtr<WebGLShader>* shaderSlot;
switch (shader->mType) {
case LOCAL_GL_VERTEX_SHADER:
shaderSlot = &mVertShader;
break;
case LOCAL_GL_FRAGMENT_SHADER:
shaderSlot = &mFragShader;
break;
default:
mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
return;
}
if (*shaderSlot != shader) {
mContext->ErrorInvalidOperation("detachShader: `shader` is not attached.");
return;
}
*shaderSlot = nullptr;
mContext->MakeContextCurrent();
mContext->gl->fDetachShader(mGLName, shader->mGLName);
}
already_AddRefed<WebGLActiveInfo>
WebGLProgram::GetActiveAttrib(GLuint index) const
{
if (!mMostRecentLinkInfo) {
RefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid(mContext);
return ret.forget();
}
const auto& activeList = mMostRecentLinkInfo->activeAttribs;
if (index >= activeList.size()) {
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
index, "ACTIVE_ATTRIBS", activeList.size());
return nullptr;
}
RefPtr<WebGLActiveInfo> ret = activeList[index];
return ret.forget();
}
already_AddRefed<WebGLActiveInfo>
WebGLProgram::GetActiveUniform(GLuint index) const
{
if (!mMostRecentLinkInfo) {
// According to the spec, this can return null.
RefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid(mContext);
return ret.forget();
}
const auto& activeList = mMostRecentLinkInfo->activeUniforms;
if (index >= activeList.size()) {
mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
index, "ACTIVE_UNIFORMS", activeList.size());
return nullptr;
}
RefPtr<WebGLActiveInfo> ret = activeList[index];
return ret.forget();
}
void
WebGLProgram::GetAttachedShaders(nsTArray<RefPtr<WebGLShader>>* const out) const
{
out->TruncateLength(0);
if (mVertShader)
out->AppendElement(mVertShader);
if (mFragShader)
out->AppendElement(mFragShader);
}
GLint
WebGLProgram::GetAttribLocation(const nsAString& userName_wide) const
{
if (!ValidateGLSLVariableName(userName_wide, mContext, "getAttribLocation"))
return -1;
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getAttribLocation: `program` must be linked.");
return -1;
}
const NS_LossyConvertUTF16toASCII userName(userName_wide);
const WebGLActiveInfo* info;
if (!LinkInfo()->FindAttrib(userName, &info))
return -1;
const nsCString& mappedName = info->mBaseMappedName;
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
return gl->fGetAttribLocation(mGLName, mappedName.BeginReading());
}
GLint
WebGLProgram::GetFragDataLocation(const nsAString& userName_wide) const
{
if (!ValidateGLSLVariableName(userName_wide, mContext, "getFragDataLocation"))
return -1;
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getFragDataLocation: `program` must be linked.");
return -1;
}
const NS_LossyConvertUTF16toASCII userName(userName_wide);
nsCString mappedName;
if (!LinkInfo()->FindFragData(userName, &mappedName))
return -1;
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
return gl->fGetFragDataLocation(mGLName, mappedName.BeginReading());
}
void
WebGLProgram::GetProgramInfoLog(nsAString* const out) const
{
CopyASCIItoUTF16(mLinkLog, *out);
}
static GLint
GetProgramiv(gl::GLContext* gl, GLuint program, GLenum pname)
{
GLint ret = 0;
gl->fGetProgramiv(program, pname, &ret);
return ret;
}
JS::Value
WebGLProgram::GetProgramParameter(GLenum pname) const
{
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
if (mContext->IsWebGL2()) {
switch (pname) {
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
return JS::Int32Value(mTransformFeedbackVaryings.size());
}
}
switch (pname) {
case LOCAL_GL_ATTACHED_SHADERS:
case LOCAL_GL_ACTIVE_UNIFORMS:
case LOCAL_GL_ACTIVE_ATTRIBUTES:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
case LOCAL_GL_DELETE_STATUS:
return JS::BooleanValue(IsDeleteRequested());
case LOCAL_GL_LINK_STATUS:
return JS::BooleanValue(IsLinked());
case LOCAL_GL_VALIDATE_STATUS:
#ifdef XP_MACOSX
// See comment in ValidateProgram.
if (gl->WorkAroundDriverBugs())
return JS::BooleanValue(true);
#endif
return JS::BooleanValue(bool(GetProgramiv(gl, mGLName, pname)));
default:
mContext->ErrorInvalidEnumInfo("getProgramParameter: `pname`",
pname);
return JS::NullValue();
}
}
GLuint
WebGLProgram::GetUniformBlockIndex(const nsAString& userName_wide) const
{
if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformBlockIndex"))
return LOCAL_GL_INVALID_INDEX;
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getUniformBlockIndex: `program` must be linked.");
return LOCAL_GL_INVALID_INDEX;
}
const NS_LossyConvertUTF16toASCII userName(userName_wide);
nsDependentCString baseUserName;
bool isArray;
size_t arrayIndex;
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
return LOCAL_GL_INVALID_INDEX;
RefPtr<const webgl::UniformBlockInfo> info;
if (!LinkInfo()->FindUniformBlock(baseUserName, &info)) {
return LOCAL_GL_INVALID_INDEX;
}
const nsCString& baseMappedName = info->mBaseMappedName;
nsAutoCString mappedName(baseMappedName);
if (isArray) {
mappedName.AppendLiteral("[");
mappedName.AppendInt(uint32_t(arrayIndex));
mappedName.AppendLiteral("]");
}
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
return gl->fGetUniformBlockIndex(mGLName, mappedName.BeginReading());
}
void
WebGLProgram::GetActiveUniformBlockName(GLuint uniformBlockIndex, nsAString& retval) const
{
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint) linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
return;
}
const webgl::UniformBlockInfo* blockInfo = linkInfo->uniformBlocks[uniformBlockIndex];
retval.Assign(NS_ConvertASCIItoUTF16(blockInfo->mBaseUserName));
}
void
WebGLProgram::GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname,
dom::Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval) const
{
retval.SetNull();
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
return;
}
gl::GLContext* gl = mContext->GL();
GLint param = 0;
switch (pname) {
case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
retval.SetValue().SetAsBoolean() = (param != 0);
return;
case LOCAL_GL_UNIFORM_BLOCK_BINDING:
case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
retval.SetValue().SetAsUnsignedLong() = param;
return;
}
}
void
WebGLProgram::GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex,
dom::Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval,
ErrorResult& rv) const
{
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
return;
}
gl::GLContext* gl = mContext->GL();
GLint activeUniformCount = 0;
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
&activeUniformCount);
JS::RootedObject obj(cx, dom::Uint32Array::Create(cx, mContext, activeUniformCount,
nullptr));
if (!obj) {
rv = NS_ERROR_OUT_OF_MEMORY;
return;
}
dom::Uint32Array result;
DebugOnly<bool> inited = result.Init(obj);
MOZ_ASSERT(inited);
result.ComputeLengthAndData();
gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
(GLint*)result.Data());
inited = retval.SetValue().SetAsUint32Array().Init(obj);
MOZ_ASSERT(inited);
}
already_AddRefed<WebGLUniformLocation>
WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
{
if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformLocation"))
return nullptr;
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
return nullptr;
}
const NS_LossyConvertUTF16toASCII userName(userName_wide);
nsDependentCString baseUserName;
bool isArray;
size_t arrayIndex;
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
return nullptr;
const WebGLActiveInfo* activeInfo;
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo))
return nullptr;
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
nsAutoCString mappedName(baseMappedName);
if (isArray) {
mappedName.AppendLiteral("[");
mappedName.AppendInt(uint32_t(arrayIndex));
mappedName.AppendLiteral("]");
}
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
GLint loc = gl->fGetUniformLocation(mGLName, mappedName.BeginReading());
if (loc == -1)
return nullptr;
RefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
loc, activeInfo);
return locObj.forget();
}
void
WebGLProgram::GetUniformIndices(const dom::Sequence<nsString>& uniformNames,
dom::Nullable< nsTArray<GLuint> >& retval) const
{
size_t count = uniformNames.Length();
nsTArray<GLuint>& arr = retval.SetValue();
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
for (size_t i = 0; i < count; i++) {
const NS_LossyConvertUTF16toASCII userName(uniformNames[i]);
nsDependentCString baseUserName;
bool isArray;
size_t arrayIndex;
if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex)) {
arr.AppendElement(LOCAL_GL_INVALID_INDEX);
continue;
}
const WebGLActiveInfo* activeInfo;
if (!LinkInfo()->FindUniform(baseUserName, &activeInfo)) {
arr.AppendElement(LOCAL_GL_INVALID_INDEX);
continue;
}
const nsCString& baseMappedName = activeInfo->mBaseMappedName;
nsAutoCString mappedName(baseMappedName);
if (isArray) {
mappedName.AppendLiteral("[");
mappedName.AppendInt(uint32_t(arrayIndex));
mappedName.AppendLiteral("]");
}
const GLchar* mappedNameBytes = mappedName.BeginReading();
GLuint index = 0;
gl->fGetUniformIndices(mGLName, 1, &mappedNameBytes, &index);
arr.AppendElement(index);
}
}
void
WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const
{
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
return;
}
const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
if (uniformBlockIndex >= uniformBlockCount) {
mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
return;
}
if (uniformBlockBinding > mContext->mGLMaxUniformBufferBindings) {
mContext->ErrorInvalidEnum("getActiveUniformBlockName: binding %u invalid.", uniformBlockBinding);
return;
}
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
}
bool
WebGLProgram::LinkProgram()
{
mContext->InvalidateBufferFetching(); // we do it early in this function
// as some of the validation below changes program state
mLinkLog.Truncate();
mMostRecentLinkInfo = nullptr;
if (!mVertShader || !mVertShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
if (!mFragShader || !mFragShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
if (gl->WorkAroundDriverBugs() &&
mContext->mIsMesa)
{
// Bug 777028: Mesa can't handle more than 16 samplers per program,
// counting each array entry.
size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
mFragShader->CalcNumSamplerUniforms();
if (numSamplerUniforms_upperBound > 16) {
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
" Mesa drivers to avoid crashing.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
// Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count.
if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max attribute count.");
mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
return false;
}
}
// Bind the attrib locations.
// This can't be done trivially, because we have to deal with mapped attrib names.
for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
const nsCString& name = itr->first;
GLuint index = itr->second;
mVertShader->BindAttribLocation(mGLName, name, index);
}
if (!mTransformFeedbackVaryings.empty()) {
// Bind the transform feedback varyings.
// This can't be done trivially, because we have to deal with mapped names too.
mVertShader->ApplyTransformFeedbackVaryings(mGLName,
mTransformFeedbackVaryings,
mTransformFeedbackBufferMode,
&mTempMappedVaryings);
}
if (LinkAndUpdate())
return true;
// Failed link.
if (mContext->ShouldGenerateWarnings()) {
// report shader/program infoLogs as warnings.
// note that shader compilation errors can be deferred to linkProgram,
// which is why we can't do anything in compileShader. In practice we could
// report in compileShader the translation errors generated by ANGLE,
// but it seems saner to keep a single way of obtaining shader infologs.
if (!mLinkLog.IsEmpty()) {
mContext->GenerateWarning("linkProgram: Failed to link, leaving the following"
" log:\n%s\n",
mLinkLog.BeginReading());
}
}
return false;
}
bool
WebGLProgram::UseProgram() const
{
if (!mMostRecentLinkInfo) {
mContext->ErrorInvalidOperation("useProgram: Program has not been successfully"
" linked.");
return false;
}
mContext->MakeContextCurrent();
mContext->InvalidateBufferFetching();
mContext->gl->fUseProgram(mGLName);
return true;
}
void
WebGLProgram::ValidateProgram() const
{
mContext->MakeContextCurrent();
gl::GLContext* gl = mContext->gl;
#ifdef XP_MACOSX
// See bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed
// with Mac OS 10.6.7.
if (gl->WorkAroundDriverBugs()) {
mContext->GenerateWarning("validateProgram: Implemented as a no-op on"
" Mac to work around crashes.");
return;
}
#endif
gl->fValidateProgram(mGLName);
}
////////////////////////////////////////////////////////////////////////////////
bool
WebGLProgram::LinkAndUpdate()
{
mMostRecentLinkInfo = nullptr;
gl::GLContext* gl = mContext->gl;
gl->fLinkProgram(mGLName);
// Grab the program log.
GLuint logLenWithNull = 0;
gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&logLenWithNull);
if (logLenWithNull > 1) {
mLinkLog.SetLength(logLenWithNull - 1);
gl->fGetProgramInfoLog(mGLName, logLenWithNull, nullptr, mLinkLog.BeginWriting());
} else {
mLinkLog.SetLength(0);
}
// Post link, temporary mapped varying names for transform feedback can be discarded.
// The memory can only be deleted after log is queried or the link status will fail.
std::vector<std::string> empty;
empty.swap(mTempMappedVaryings);
GLint ok = 0;
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
if (!ok)
return false;
mMostRecentLinkInfo = QueryProgramInfo(this, gl);
MOZ_ASSERT(mMostRecentLinkInfo);
if (!mMostRecentLinkInfo)
mLinkLog.AssignLiteral("Failed to gather program info.");
return mMostRecentLinkInfo;
}
bool
WebGLProgram::FindAttribUserNameByMappedName(const nsACString& mappedName,
nsDependentCString* const out_userName) const
{
if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName))
return true;
return false;
}
bool
WebGLProgram::FindVaryingByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const
{
if (mVertShader->FindVaryingByMappedName(mappedName, out_userName, out_isArray))
return true;
return false;
}
bool
WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const
{
if (mVertShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
return true;
if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
return true;
return false;
}
void
WebGLProgram::TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
GLenum bufferMode)
{
if (bufferMode != LOCAL_GL_INTERLEAVED_ATTRIBS &&
bufferMode != LOCAL_GL_SEPARATE_ATTRIBS)
{
mContext->ErrorInvalidEnum("transformFeedbackVaryings: `bufferMode` %s is "
"invalid. Must be one of gl.INTERLEAVED_ATTRIBS or "
"gl.SEPARATE_ATTRIBS.",
mContext->EnumName(bufferMode));
return;
}
size_t varyingsCount = varyings.Length();
if (bufferMode == LOCAL_GL_SEPARATE_ATTRIBS &&
varyingsCount >= mContext->mGLMaxTransformFeedbackSeparateAttribs)
{
mContext->ErrorInvalidValue("transformFeedbackVaryings: Number of `varyings` exc"
"eeds gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS.");
return;
}
std::vector<nsCString> asciiVaryings;
for (size_t i = 0; i < varyingsCount; i++) {
if (!ValidateGLSLVariableName(varyings[i], mContext, "transformFeedbackVaryings"))
return;
NS_LossyConvertUTF16toASCII asciiName(varyings[i]);
asciiVaryings.push_back(asciiName);
}
// All validated. Translate the strings and store them until
// program linking.
mTransformFeedbackBufferMode = bufferMode;
mTransformFeedbackVaryings.swap(asciiVaryings);
}
already_AddRefed<WebGLActiveInfo>
WebGLProgram::GetTransformFeedbackVarying(GLuint index)
{
// No docs in the WebGL 2 spec for this function. Taking the language for
// getActiveAttrib, which states that the function returns null on any error.
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getTransformFeedbackVarying: `program` must be "
"linked.");
return nullptr;
}
if (index >= LinkInfo()->transformFeedbackVaryings.size()) {
mContext->ErrorInvalidValue("getTransformFeedbackVarying: `index` is greater or "
"equal to TRANSFORM_FEEDBACK_VARYINGS.");
return nullptr;
}
RefPtr<WebGLActiveInfo> ret = LinkInfo()->transformFeedbackVaryings[index];
return ret.forget();
}
bool
WebGLProgram::FindUniformBlockByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const
{
if (mVertShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
return true;
if (mFragShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
JSObject*
WebGLProgram::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLProgramBinding::Wrap(js, this, givenProto);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
} // namespace mozilla