Bug 1404196 - Simplify and repair vertex fetch. - r=daoshengmu

MozReview-Commit-ID: FL7uibuv4VY
This commit is contained in:
Jeff Gilbert 2017-10-20 15:40:12 -07:00
Родитель cebb6665ed
Коммит d6af1e81ba
12 изменённых файлов: 393 добавлений и 425 удалений

Просмотреть файл

@ -59,7 +59,10 @@ WebGLBuffer::Delete()
{
mContext->MakeContextCurrent();
mContext->gl->fDeleteBuffers(1, &mGLName);
mByteLength = 0;
mFetchInvalidator.InvalidateCaches();
mIndexCache = nullptr;
mIndexRanges.clear();
LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers
@ -138,8 +141,6 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa
const bool sizeChanges = (size != ByteLength());
if (sizeChanges) {
mContext->InvalidateBufferFetching();
gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fBufferData(target, size, uploadData, usage);
const auto error = errorScope.GetError();
@ -157,6 +158,7 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa
mUsage = usage;
mByteLength = size;
mFetchInvalidator.InvalidateCaches();
mIndexCache = Move(newIndexCache);
if (mIndexCache) {
@ -234,18 +236,18 @@ IndexByteSizeByType(GLenum type)
}
void
WebGLBuffer::InvalidateCacheRange(size_t byteOffset, size_t byteLength) const
WebGLBuffer::InvalidateCacheRange(uint64_t byteOffset, uint64_t byteLength) const
{
MOZ_ASSERT(mIndexCache);
std::vector<IndexRange> invalids;
const size_t updateBegin = byteOffset;
const size_t updateEnd = updateBegin + byteLength;
const uint64_t updateBegin = byteOffset;
const uint64_t updateEnd = updateBegin + byteLength;
for (const auto& cur : mIndexRanges) {
const auto& range = cur.first;
const auto& indexByteSize = IndexByteSizeByType(range.type);
const size_t rangeBegin = range.first * indexByteSize;
const size_t rangeEnd = rangeBegin + range.count*indexByteSize;
const auto rangeBegin = range.byteOffset * indexByteSize;
const auto rangeEnd = rangeBegin + uint64_t(range.indexCount) * indexByteSize;
if (rangeBegin >= updateEnd || rangeEnd <= updateBegin)
continue;
invalids.push_back(range);
@ -273,48 +275,47 @@ WebGLBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
}
template<typename T>
static size_t
MaxForRange(const void* data, size_t first, size_t count, const uint32_t ignoredVal)
static Maybe<uint32_t>
MaxForRange(const void* const start, const uint32_t count,
const Maybe<uint32_t>& untypedIgnoredVal)
{
const T ignoredTVal(ignoredVal);
T ret = 0;
const Maybe<T> ignoredVal = (untypedIgnoredVal ? Some(T(untypedIgnoredVal.value()))
: Nothing());
Maybe<uint32_t> maxVal;
auto itr = (const T*)data + first;
auto itr = (const T*)start;
const auto end = itr + count;
for (; itr != end; ++itr) {
const auto& val = *itr;
if (val <= ret)
if (ignoredVal && val == ignoredVal.value())
continue;
if (val == ignoredTVal)
if (maxVal && val <= maxVal.value())
continue;
ret = val;
maxVal = Some(val);
}
return size_t(ret);
return maxVal;
}
const uint32_t kMaxIndexRanges = 256;
static const uint32_t kMaxIndexRanges = 256;
bool
WebGLBuffer::ValidateIndexedFetch(GLenum type, uint32_t numFetchable, size_t first,
size_t count) const
Maybe<uint32_t>
WebGLBuffer::GetIndexedFetchMaxVert(const GLenum type, const uint64_t byteOffset,
const uint32_t indexCount) const
{
if (!mIndexCache)
return true;
return Nothing();
if (!count)
return true;
const IndexRange range = { type, first, count };
auto res = mIndexRanges.insert({ range, size_t(0) });
const IndexRange range = { type, byteOffset, indexCount };
auto res = mIndexRanges.insert({ range, Nothing() });
if (mIndexRanges.size() > kMaxIndexRanges) {
mContext->GeneratePerfWarning("[%p] Clearing mIndexRanges after exceeding %u.",
this, kMaxIndexRanges);
mIndexRanges.clear();
res = mIndexRanges.insert({ range, size_t(0) });
res = mIndexRanges.insert({ range, Nothing() });
}
const auto& itr = res.first;
@ -323,29 +324,37 @@ WebGLBuffer::ValidateIndexedFetch(GLenum type, uint32_t numFetchable, size_t fir
auto& maxFetchIndex = itr->second;
if (didInsert) {
const auto& data = mIndexCache.get();
const uint32_t ignoreVal = (mContext->IsWebGL2() ? UINT32_MAX : 0);
const auto start = (const uint8_t*)data + byteOffset;
Maybe<uint32_t> ignoredVal;
if (mContext->IsWebGL2()) {
ignoredVal = Some(UINT32_MAX);
}
switch (type) {
case LOCAL_GL_UNSIGNED_BYTE:
maxFetchIndex = MaxForRange<uint8_t>(data, first, count, ignoreVal);
maxFetchIndex = MaxForRange<uint8_t>(start, indexCount, ignoredVal);
break;
case LOCAL_GL_UNSIGNED_SHORT:
maxFetchIndex = MaxForRange<uint16_t>(data, first, count, ignoreVal);
maxFetchIndex = MaxForRange<uint16_t>(start, indexCount, ignoredVal);
break;
case LOCAL_GL_UNSIGNED_INT:
maxFetchIndex = MaxForRange<uint32_t>(data, first, count, ignoreVal);
maxFetchIndex = MaxForRange<uint32_t>(start, indexCount, ignoredVal);
break;
default:
MOZ_CRASH();
}
mContext->GeneratePerfWarning("[%p] New range #%u: (0x%04x, %u, %u): %u", this,
uint32_t(mIndexRanges.size()), type,
uint32_t(first), uint32_t(count),
uint32_t(maxFetchIndex));
const auto displayMaxVertIndex = maxFetchIndex ? int64_t(maxFetchIndex.value())
: -1;
mContext->GeneratePerfWarning("[%p] New range #%u: (0x%04x, %" PRIu64 ", %u):"
" %" PRIi64,
this, uint32_t(mIndexRanges.size()), range.type,
range.byteOffset, range.indexCount,
displayMaxVertIndex);
}
return maxFetchIndex < numFetchable;
return maxFetchIndex;
}
////

Просмотреть файл

@ -8,6 +8,7 @@
#include <map>
#include "CacheMap.h"
#include "GLDefs.h"
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
@ -44,7 +45,8 @@ public:
GLenum Usage() const { return mUsage; }
size_t ByteLength() const { return mByteLength; }
bool ValidateIndexedFetch(GLenum type, uint32_t max_allowed, size_t first, size_t count) const;
Maybe<uint32_t> GetIndexedFetchMaxVert(GLenum type, uint64_t byteOffset,
uint32_t indexCount) const;
bool ValidateRange(const char* funcName, size_t byteOffset, size_t byteLen) const;
WebGLContext* GetParentObject() const {
@ -67,6 +69,7 @@ public:
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
MOZ_ASSERT_IF(addVal < 0, buffer->mTFBindCount >= size_t(-addVal));
buffer->mTFBindCount += addVal;
buffer->mFetchInvalidator.InvalidateCaches();
} else {
MOZ_ASSERT_IF(addVal < 0, buffer->mNonTFBindCount >= size_t(-addVal));
buffer->mNonTFBindCount += addVal;
@ -95,7 +98,7 @@ public:
protected:
~WebGLBuffer();
void InvalidateCacheRange(size_t offset, size_t length) const;
void InvalidateCacheRange(uint64_t byteOffset, uint64_t byteLength) const;
Kind mContent;
GLenum mUsage;
@ -105,22 +108,25 @@ protected:
struct IndexRange final {
GLenum type;
size_t first;
size_t count;
uint64_t byteOffset;
uint32_t indexCount;
bool operator<(const IndexRange& x) const {
if (type != x.type)
return type < x.type;
if (first != x.first)
return first < x.first;
if (byteOffset != x.byteOffset)
return byteOffset < x.byteOffset;
return count < x.count;
return indexCount < x.indexCount;
}
};
UniqueBuffer mIndexCache;
mutable std::map<IndexRange, size_t> mIndexRanges;
mutable std::map<IndexRange, Maybe<uint32_t>> mIndexRanges;
public:
CacheMapInvalidator mFetchInvalidator;
};
} // namespace mozilla

Просмотреть файл

@ -112,10 +112,6 @@ WebGLContext::WebGLContext()
, mNumPerfWarnings(0)
, mMaxAcceptableFBStatusInvals(gfxPrefs::WebGLMaxAcceptableFBStatusInvals())
, mDataAllocGLCallCount(0)
, mBufferFetchingIsVerified(false)
, mBufferFetchingHasPerVertex(false)
, mMaxFetchedVertices(0)
, mMaxFetchedInstances(0)
, mBypassShaderValidation(false)
, mEmptyTFO(0)
, mContextLossHandler(this)
@ -184,8 +180,6 @@ WebGLContext::WebGLContext()
mLastUseIndex = 0;
InvalidateBufferFetching();
mDisableFragHighP = false;
mDrawCallsSinceLastFlush = 0;
@ -2303,6 +2297,27 @@ Intersect(const int32_t srcSize, const int32_t read0, const int32_t readSize,
return true;
}
// --
uint64_t
AvailGroups(const uint64_t totalAvailItems, const uint64_t firstItemOffset,
const uint32_t groupSize, const uint32_t groupStride)
{
MOZ_ASSERT(groupSize && groupStride);
MOZ_ASSERT(groupSize <= groupStride);
if (totalAvailItems <= firstItemOffset)
return 0;
const size_t availItems = totalAvailItems - firstItemOffset;
size_t availGroups = availItems / groupStride;
const size_t tailItems = availItems % groupStride;
if (tailItems >= groupSize) {
availGroups += 1;
}
return availGroups;
}
////////////////////////////////////////////////////////////////////////////////
CheckedUint32
@ -2418,8 +2433,7 @@ WebGLContext::ValidateArrayBufferView(const char* funcName,
return true;
}
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
////
void
WebGLContext::UpdateMaxDrawBuffers()
@ -2434,6 +2448,9 @@ WebGLContext::UpdateMaxDrawBuffers()
mGLMaxDrawBuffers = std::min(mGLMaxDrawBuffers, mGLMaxColorAttachments);
}
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const std::vector<IndexedBufferBinding>& field,

Просмотреть файл

@ -34,6 +34,7 @@
#endif
// Local
#include "CacheMap.h"
#include "WebGLContextLossHandler.h"
#include "WebGLContextUnchecked.h"
#include "WebGLFormats.h"
@ -293,6 +294,7 @@ class WebGLContext
friend class WebGLExtensionLoseContext;
friend class WebGLExtensionVertexArray;
friend class WebGLMemoryTracker;
friend struct webgl::LinkedProgramInfo;
friend struct webgl::UniformBlockInfo;
enum {
@ -1390,20 +1392,11 @@ public:
void VertexAttribDivisor(GLuint index, GLuint divisor);
private:
// Cache the max number of vertices and instances that can be read from
// bound VBOs (result of ValidateBuffers).
bool mBufferFetchingIsVerified;
bool mBufferFetchingHasPerVertex;
uint32_t mMaxFetchedVertices;
uint32_t mMaxFetchedInstances;
bool mBufferFetch_IsAttrib0Active;
bool DrawArrays_check(const char* funcName, GLenum mode, GLint first,
GLsizei vertCount, GLsizei instanceCount);
bool DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
GLenum type, WebGLintptr byteOffset,
GLsizei instanceCount);
bool DrawInstanced_check(const char* info);
bool DrawArrays_check(const char* funcName, GLint first, GLsizei vertCount,
GLsizei instanceCount, Maybe<uint32_t>* out_lastVert);
bool DrawElements_check(const char* funcName, GLsizei indexCount, GLenum type,
WebGLintptr byteOffset, GLsizei instanceCount,
Maybe<uint32_t>* out_lastVert);
void Draw_cleanup(const char* funcName);
void VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
@ -1415,7 +1408,6 @@ private:
void VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
const GLfloat* ptr);
bool ValidateBufferFetching(const char* info);
bool BindArrayAttribToLocation0(WebGLProgram* prog);
// -----------------------------------------------------------------------------
@ -1425,14 +1417,6 @@ protected:
bool DoFakeVertexAttrib0(const char* funcName, GLuint vertexCount);
void UndoFakeVertexAttrib0();
inline void InvalidateBufferFetching()
{
mBufferFetchingIsVerified = false;
mBufferFetchingHasPerVertex = false;
mMaxFetchedVertices = 0;
mMaxFetchedInstances = 0;
}
CheckedUint32 mGeneration;
WebGLContextOptions mOptions;
@ -1927,6 +1911,7 @@ protected:
// useful to vertex shaders, but is global state.
UniquePtr<GLenum[]> mGenericVertexAttribTypes;
uint8_t mGenericVertexAttrib0Data[sizeof(float) * 4];
CacheMapInvalidator mGenericVertexAttribTypeInvalidator;
GLuint mFakeVertexAttrib0BufferObject;
size_t mFakeVertexAttrib0BufferObjectSize;
@ -2189,6 +2174,10 @@ bool
Intersect(int32_t srcSize, int32_t read0, int32_t readSize, int32_t* out_intRead0,
int32_t* out_intWrite0, int32_t* out_intSize);
uint64_t
AvailGroups(uint64_t totalAvailItems, uint64_t firstItemOffset, uint32_t groupSize,
uint32_t groupStride);
////
void

Просмотреть файл

@ -501,8 +501,6 @@ WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
////
buffer->RequestDelete();
InvalidateBufferFetching();
}
bool

Просмотреть файл

@ -5,6 +5,7 @@
#include "WebGLContext.h"
#include "GeckoProfiler.h"
#include "GLContext.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/UniquePtrExtensions.h"
@ -230,79 +231,6 @@ WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fa
////////////////////////////////////////
bool
WebGLContext::DrawInstanced_check(const char* info)
{
MOZ_ASSERT(IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays));
if (!mBufferFetchingHasPerVertex) {
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
* If all of the enabled vertex attribute arrays that are bound to active
* generic attributes in the program have a non-zero divisor, the draw
* call should return INVALID_OPERATION.
*
* NB: This also appears to apply to NV_instanced_arrays, though the
* INVALID_OPERATION emission is not explicitly stated.
* ARB_instanced_arrays does not have this restriction.
*/
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
return false;
}
return true;
}
bool
WebGLContext::DrawArrays_check(const char* funcName, GLenum mode, GLint first,
GLsizei vertCount, GLsizei instanceCount)
{
if (!ValidateDrawModeEnum(mode, funcName))
return false;
if (!ValidateNonNegative(funcName, "first", first) ||
!ValidateNonNegative(funcName, "vertCount", vertCount) ||
!ValidateNonNegative(funcName, "instanceCount", instanceCount))
{
return false;
}
if (!ValidateStencilParamsForDrawCall())
return false;
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
if (mPrimRestartTypeBytes != 0) {
mPrimRestartTypeBytes = 0;
// OSX appears to have severe perf issues with leaving this enabled.
gl->fDisable(LOCAL_GL_PRIMITIVE_RESTART);
}
}
if (!vertCount || !instanceCount)
return false; // No error, just early out.
if (!ValidateBufferFetching(funcName))
return false;
const auto checked_firstPlusCount = CheckedInt<GLsizei>(first) + vertCount;
if (!checked_firstPlusCount.isValid()) {
ErrorInvalidOperation("%s: overflow in first+vertCount", funcName);
return false;
}
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
ErrorInvalidOperation("%s: Bound vertex attribute buffers do not have sufficient"
" size for given first and count.",
funcName);
return false;
}
return true;
}
////////////////////////////////////////
template<typename T>
static bool
DoSetsIntersect(const std::set<T>& a, const std::set<T>& b)
@ -319,21 +247,25 @@ class ScopedDrawHelper final
bool mDidFake;
public:
ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
uint32_t vertCount, uint32_t instanceCount, bool* const out_error)
ScopedDrawHelper(WebGLContext* const webgl, const char* const funcName,
const GLenum mode, const Maybe<uint32_t>& lastRequiredVertex,
const uint32_t instanceCount, bool* const out_error)
: mWebGL(webgl)
, mDidFake(false)
{
if (instanceCount > mWebGL->mMaxFetchedInstances) {
mWebGL->ErrorInvalidOperation("%s: Bound instance attribute buffers do not"
" have sufficient size for given"
" `instanceCount`.",
funcName);
MOZ_ASSERT(mWebGL->gl->IsCurrent());
if (!mWebGL->ValidateDrawModeEnum(mode, funcName)) {
*out_error = true;
return;
}
MOZ_ASSERT(mWebGL->gl->IsCurrent());
if (!mWebGL->ValidateStencilParamsForDrawCall()) {
*out_error = true;
return;
}
////
if (mWebGL->mBoundDrawFramebuffer) {
if (!mWebGL->mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName)) {
@ -344,15 +276,6 @@ public:
mWebGL->ClearBackbufferIfNeeded();
}
////
const size_t requiredVerts = firstVertex + vertCount;
if (!mWebGL->DoFakeVertexAttrib0(funcName, requiredVerts)) {
*out_error = true;
return;
}
mDidFake = true;
////
// Check UBO sizes.
@ -419,39 +342,39 @@ public:
////
for (const auto& progAttrib : linkInfo->attribs) {
const auto& loc = progAttrib.mLoc;
if (loc == -1)
continue;
const auto& fetchLimits = linkInfo->GetDrawFetchLimits(funcName);
if (!fetchLimits) {
*out_error = true;
return;
}
const auto& attribData = mWebGL->mBoundVertexArray->mAttribs[loc];
GLenum attribDataBaseType;
if (attribData.mEnabled) {
attribDataBaseType = attribData.BaseType();
if (attribData.mBuf->IsBoundForTF()) {
mWebGL->ErrorInvalidOperation("%s: Vertex attrib %u's buffer is bound"
" or in use for transform feedback.",
funcName, loc);
*out_error = true;
return;
}
} else {
attribDataBaseType = mWebGL->mGenericVertexAttribTypes[loc];
}
if (attribDataBaseType != progAttrib.mBaseType) {
nsCString progType, dataType;
WebGLContext::EnumName(progAttrib.mBaseType, &progType);
WebGLContext::EnumName(attribDataBaseType, &dataType);
mWebGL->ErrorInvalidOperation("%s: Vertex attrib %u requires data of type"
" %s, but is being supplied with type %s.",
funcName, loc, progType.BeginReading(),
dataType.BeginReading());
if (lastRequiredVertex && instanceCount) {
if (lastRequiredVertex.value() >= fetchLimits->maxVerts) {
mWebGL->ErrorInvalidOperation("%s: Vertex fetch requires vertex #%u, but"
" attribs only supply %" PRIu64 ".",
funcName, lastRequiredVertex.value(),
fetchLimits->maxVerts);
*out_error = true;
return;
}
if (instanceCount > fetchLimits->maxInstances) {
mWebGL->ErrorInvalidOperation("%s: Instance fetch requires %u, but"
" attribs only supply %" PRIu64 ".",
funcName, instanceCount,
fetchLimits->maxInstances);
*out_error = true;
return;
}
}
////
if (lastRequiredVertex) {
if (!mWebGL->DoFakeVertexAttrib0(funcName, lastRequiredVertex.value())) {
*out_error = true;
return;
}
mDidFake = true;
}
////
@ -548,6 +471,41 @@ public:
////////////////////////////////////////
bool
WebGLContext::DrawArrays_check(const char* const funcName, const GLint first,
const GLsizei vertCount, const GLsizei instanceCount,
Maybe<uint32_t>* const out_lastVert)
{
if (!ValidateNonNegative(funcName, "first", first) ||
!ValidateNonNegative(funcName, "vertCount", vertCount) ||
!ValidateNonNegative(funcName, "instanceCount", instanceCount))
{
return false;
}
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
if (mPrimRestartTypeBytes != 0) {
mPrimRestartTypeBytes = 0;
// OSX appears to have severe perf issues with leaving this enabled.
gl->fDisable(LOCAL_GL_PRIMITIVE_RESTART);
}
}
if (!vertCount) {
*out_lastVert = Nothing();
} else {
const auto lastVert_checked = CheckedInt<uint32_t>(first) + vertCount - 1;
if (!lastVert_checked.isValid()) {
ErrorOutOfMemory("%s: `first+vertCount` out of range.", funcName);
return false;
}
*out_lastVert = Some(lastVert_checked.value());
}
return true;
}
void
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei vertCount)
{
@ -564,10 +522,12 @@ WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei vertCount)
return;
const GLsizei instanceCount = 1;
if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
Maybe<uint32_t> lastVert;
if (!DrawArrays_check(funcName, first, vertCount, instanceCount, &lastVert))
return;
const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error);
if (error)
return;
@ -578,8 +538,10 @@ WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei vertCount)
{
ScopedDrawCallWrapper wrapper(*this);
AUTO_PROFILER_LABEL("glDrawArrays", GRAPHICS);
gl->fDrawArrays(mode, first, vertCount);
if (vertCount) {
AUTO_PROFILER_LABEL("glDrawArrays", GRAPHICS);
gl->fDrawArrays(mode, first, vertCount);
}
}
Draw_cleanup(funcName);
@ -602,13 +564,12 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
if (error)
return;
if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
Maybe<uint32_t> lastVert;
if (!DrawArrays_check(funcName, first, vertCount, instanceCount, &lastVert))
return;
if (!DrawInstanced_check(funcName))
return;
const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error);
if (error)
return;
@ -619,8 +580,10 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
{
ScopedDrawCallWrapper wrapper(*this);
AUTO_PROFILER_LABEL("glDrawArraysInstanced", GRAPHICS);
gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
if (vertCount && instanceCount) {
AUTO_PROFILER_LABEL("glDrawArraysInstanced", GRAPHICS);
gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
}
}
Draw_cleanup(funcName);
@ -630,13 +593,11 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
////////////////////////////////////////
bool
WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
GLenum type, WebGLintptr byteOffset,
GLsizei instanceCount)
WebGLContext::DrawElements_check(const char* const funcName, const GLsizei rawIndexCount,
const GLenum type, const WebGLintptr byteOffset,
const GLsizei instanceCount,
Maybe<uint32_t>* const out_lastVert)
{
if (!ValidateDrawModeEnum(mode, funcName))
return false;
if (mBoundTransformFeedback &&
mBoundTransformFeedback->mIsActive &&
!mBoundTransformFeedback->mIsPaused)
@ -647,42 +608,35 @@ WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vert
return false;
}
if (!ValidateNonNegative(funcName, "vertCount", vertCount) ||
if (!ValidateNonNegative(funcName, "vertCount", rawIndexCount) ||
!ValidateNonNegative(funcName, "byteOffset", byteOffset) ||
!ValidateNonNegative(funcName, "instanceCount", instanceCount))
{
return false;
}
const auto indexCount = uint32_t(rawIndexCount);
if (!ValidateStencilParamsForDrawCall())
return false;
if (!vertCount || !instanceCount)
return false; // No error, just early out.
uint8_t bytesPerElem = 0;
uint8_t bytesPerIndex = 0;
switch (type) {
case LOCAL_GL_UNSIGNED_BYTE:
bytesPerElem = 1;
bytesPerIndex = 1;
break;
case LOCAL_GL_UNSIGNED_SHORT:
bytesPerElem = 2;
bytesPerIndex = 2;
break;
case LOCAL_GL_UNSIGNED_INT:
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
bytesPerElem = 4;
bytesPerIndex = 4;
}
break;
}
if (!bytesPerElem) {
if (!bytesPerIndex) {
ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", funcName, type);
return false;
}
if (byteOffset % bytesPerElem != 0) {
if (byteOffset % bytesPerIndex != 0) {
ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
funcName);
return false;
@ -692,8 +646,8 @@ WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vert
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
if (mPrimRestartTypeBytes != bytesPerElem) {
mPrimRestartTypeBytes = bytesPerElem;
if (mPrimRestartTypeBytes != bytesPerIndex) {
mPrimRestartTypeBytes = bytesPerIndex;
const uint32_t ones = UINT32_MAX >> (32 - 8*mPrimRestartTypeBytes);
gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART);
@ -702,54 +656,28 @@ WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vert
}
////
// Index fetching
const GLsizei first = byteOffset / bytesPerElem;
const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(vertCount);
if (!indexCount || !instanceCount) {
*out_lastVert = Nothing();
return true;
}
if (!checked_byteCount.isValid()) {
ErrorInvalidValue("%s: Overflow in byteCount.", funcName);
return false;
}
if (!mBoundVertexArray->mElementArrayBuffer) {
ErrorInvalidOperation("%s: Must have element array buffer binding.", funcName);
return false;
}
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer;
if (!elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: Bound element array buffer doesn't have any data.",
funcName);
return false;
}
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
if (!checked_neededByteCount.isValid()) {
ErrorInvalidOperation("%s: Overflow in byteOffset+byteCount.", funcName);
return false;
}
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
ErrorInvalidOperation("%s: Bound element array buffer is too small for given"
" count and offset.",
funcName);
return false;
}
if (!ValidateBufferFetching(funcName))
return false;
if (!mMaxFetchedVertices ||
!elemArrayBuffer.ValidateIndexedFetch(type, mMaxFetchedVertices, first, vertCount))
{
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient "
"size for given indices from the bound element array",
funcName);
const auto& indexBuffer = mBoundVertexArray->mElementArrayBuffer;
size_t availBytes = 0;
if (indexBuffer) {
MOZ_ASSERT(!indexBuffer->IsBoundForTF(), "This should be impossible.");
availBytes = indexBuffer->ByteLength();
}
const auto availIndices = AvailGroups(availBytes, byteOffset, bytesPerIndex,
bytesPerIndex);
if (indexCount > availIndices) {
ErrorInvalidOperation("%s: Index buffer too small.", funcName);
return false;
}
*out_lastVert = indexBuffer->GetIndexedFetchMaxVert(type, byteOffset, indexCount);
return true;
}
@ -774,14 +702,13 @@ HandleDrawElementsErrors(WebGLContext* webgl, const char* funcName,
}
void
WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
WebGLContext::DrawElements(GLenum mode, GLsizei indexCount, GLenum type,
WebGLintptr byteOffset, const char* funcName)
{
AUTO_PROFILER_LABEL("WebGLContext::DrawElements", GRAPHICS);
if (!funcName) {
funcName = "drawElements";
}
if (IsContextLost())
return;
@ -793,10 +720,14 @@ WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
return;
const GLsizei instanceCount = 1;
if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
Maybe<uint32_t> lastVert;
if (!DrawElements_check(funcName, indexCount, type, byteOffset, instanceCount,
&lastVert))
{
return;
}
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error);
if (error)
return;
@ -810,9 +741,11 @@ WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
errorScope.reset(new gl::GLContext::LocalErrorScope(*gl));
}
AUTO_PROFILER_LABEL("glDrawElements", GRAPHICS);
gl->fDrawElements(mode, vertCount, type,
reinterpret_cast<GLvoid*>(byteOffset));
if (lastVert) {
AUTO_PROFILER_LABEL("glDrawElements", GRAPHICS);
gl->fDrawElements(mode, indexCount, type,
reinterpret_cast<GLvoid*>(byteOffset));
}
if (errorScope) {
HandleDrawElementsErrors(this, funcName, *errorScope);
@ -824,7 +757,7 @@ WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
}
void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei indexCount, GLenum type,
WebGLintptr byteOffset, GLsizei instanceCount)
{
AUTO_PROFILER_LABEL("WebGLContext::DrawElementsInstanced", GRAPHICS);
@ -839,13 +772,14 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
if (error)
return;
if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
Maybe<uint32_t> lastVert;
if (!DrawElements_check(funcName, indexCount, type, byteOffset, instanceCount,
&lastVert))
{
return;
}
if (!DrawInstanced_check(funcName))
return;
const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
const ScopedDrawHelper scopedHelper(this, funcName, mode, lastVert, instanceCount,
&error);
if (error)
return;
@ -859,10 +793,12 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
errorScope.reset(new gl::GLContext::LocalErrorScope(*gl));
}
AUTO_PROFILER_LABEL("glDrawElementsInstanced", GRAPHICS);
gl->fDrawElementsInstanced(mode, vertCount, type,
reinterpret_cast<GLvoid*>(byteOffset),
instanceCount);
if (lastVert && instanceCount) {
AUTO_PROFILER_LABEL("glDrawElementsInstanced", GRAPHICS);
gl->fDrawElementsInstanced(mode, indexCount, type,
reinterpret_cast<GLvoid*>(byteOffset),
instanceCount);
}
if (errorScope) {
HandleDrawElementsErrors(this, funcName, *errorScope);
@ -919,117 +855,12 @@ WebGLContext::Draw_cleanup(const char* funcName)
}
}
/*
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
* that will be legal to be read from bound VBOs.
*/
bool
WebGLContext::ValidateBufferFetching(const char* info)
{
MOZ_ASSERT(mCurrentProgram);
// Note that mCurrentProgram->IsLinked() is NOT GUARANTEED.
MOZ_ASSERT(mActiveProgramLinkInfo);
#ifdef DEBUG
GLint currentProgram = 0;
MakeContextCurrent();
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->mGLName,
"WebGL: current program doesn't agree with GL state");
#endif
if (mBufferFetchingIsVerified)
return true;
bool hasPerVertex = false;
uint32_t maxVertices = UINT32_MAX;
uint32_t maxInstances = UINT32_MAX;
const uint32_t attribCount = mBoundVertexArray->mAttribs.Length();
uint32_t i = 0;
for (const auto& vd : mBoundVertexArray->mAttribs) {
// If the attrib array isn't enabled, there's nothing to check;
// it's a static value.
if (!vd.mEnabled)
continue;
if (!vd.mBuf) {
ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %du!",
info, i);
return false;
}
++i;
}
mBufferFetch_IsAttrib0Active = false;
for (const auto& attrib : mActiveProgramLinkInfo->attribs) {
if (attrib.mLoc == -1)
continue;
const uint32_t attribLoc(attrib.mLoc);
if (attribLoc >= attribCount)
continue;
if (attribLoc == 0) {
mBufferFetch_IsAttrib0Active = true;
}
const auto& vd = mBoundVertexArray->mAttribs[attribLoc];
if (!vd.mEnabled)
continue;
const auto& bufByteLen = vd.mBuf->ByteLength();
if (vd.ByteOffset() > bufByteLen) {
maxVertices = 0;
maxInstances = 0;
break;
}
size_t availBytes = bufByteLen - vd.ByteOffset();
if (vd.BytesPerVertex() > availBytes) {
maxVertices = 0;
maxInstances = 0;
break;
}
availBytes -= vd.BytesPerVertex(); // Snip off the tail.
const size_t vertCapacity = availBytes / vd.ExplicitStride() + 1; // Add +1 for the snipped tail.
if (vd.mDivisor == 0) {
if (vertCapacity < maxVertices) {
maxVertices = vertCapacity;
}
hasPerVertex = true;
} else {
const auto curMaxInstances = CheckedInt<size_t>(vertCapacity) * vd.mDivisor;
// If this isn't valid, it's because we overflowed, which means we can support
// *too much*. Don't update maxInstances in this case.
if (curMaxInstances.isValid() &&
curMaxInstances.value() < maxInstances)
{
maxInstances = curMaxInstances.value();
}
}
}
mBufferFetchingIsVerified = true;
mBufferFetchingHasPerVertex = hasPerVertex;
mMaxFetchedVertices = maxVertices;
mMaxFetchedInstances = maxInstances;
return true;
}
WebGLVertexAttrib0Status
WebGLContext::WhatDoesVertexAttrib0Need() const
{
MOZ_ASSERT(mCurrentProgram);
MOZ_ASSERT(mActiveProgramLinkInfo);
const auto& isAttribArray0Enabled = mBoundVertexArray->mAttribs[0].mEnabled;
bool legacyAttrib0 = gl->IsCompatibilityProfile();
#ifdef XP_MACOSX
if (gl->WorkAroundDriverBugs()) {
@ -1042,23 +873,19 @@ WebGLContext::WhatDoesVertexAttrib0Need() const
if (!legacyAttrib0)
return WebGLVertexAttrib0Status::Default;
if (isAttribArray0Enabled && mBufferFetch_IsAttrib0Active)
return WebGLVertexAttrib0Status::Default;
if (!mActiveProgramLinkInfo->attrib0Active) {
// Ensure that the legacy code has enough buffer.
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
}
if (mBufferFetch_IsAttrib0Active)
return WebGLVertexAttrib0Status::EmulatedInitializedArray;
// Ensure that the legacy code has enough buffer.
return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
const auto& isAttribArray0Enabled = mBoundVertexArray->mAttribs[0].mEnabled;
return isAttribArray0Enabled ? WebGLVertexAttrib0Status::Default
: WebGLVertexAttrib0Status::EmulatedInitializedArray;
}
bool
WebGLContext::DoFakeVertexAttrib0(const char* funcName, GLuint vertexCount)
WebGLContext::DoFakeVertexAttrib0(const char* const funcName, const uint32_t lastVert)
{
if (!vertexCount) {
vertexCount = 1;
}
const auto whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
return true;
@ -1102,10 +929,12 @@ WebGLContext::DoFakeVertexAttrib0(const char* funcName, GLuint vertexCount)
////
const auto bytesPerVert = sizeof(mFakeVertexAttrib0Data);
const auto checked_dataSize = CheckedUint32(vertexCount) * bytesPerVert;
const auto checked_dataSize = (CheckedUint32(lastVert)+1) * bytesPerVert;
if (!checked_dataSize.isValid()) {
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
"with %d vertices. Try reducing the number of vertices.", vertexCount);
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0"
" array for a draw-operation with %" PRIu64 " vertices. Try"
" reducing the number of vertices.",
uint64_t(lastVert) + 1);
return false;
}
const auto dataSize = checked_dataSize.value();

Просмотреть файл

@ -753,6 +753,7 @@ WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
mGenericVertexAttribTypes.reset(new GLenum[mGLMaxVertexAttribs]);
std::fill_n(mGenericVertexAttribTypes.get(), mGLMaxVertexAttribs, LOCAL_GL_FLOAT);
mGenericVertexAttribTypeInvalidator.InvalidateCaches();
static const float kDefaultGenericVertexAttribData[4] = { 0, 0, 0, 1 };
memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData,

Просмотреть файл

@ -21,8 +21,6 @@ WebGLContext::BindVertexArray(WebGLVertexArray* array)
if (array && !ValidateObject("bindVertexArrayObject", *array))
return;
InvalidateBufferFetching();
MakeContextCurrent();
if (mBoundVertexArray) {

Просмотреть файл

@ -82,6 +82,7 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfl
////
mGenericVertexAttribTypes[index] = LOCAL_GL_FLOAT;
mGenericVertexAttribTypeInvalidator.InvalidateCaches();
if (!index) {
const float data[4] = { x, y, z, w };
@ -113,6 +114,7 @@ WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w,
////
mGenericVertexAttribTypes[index] = LOCAL_GL_INT;
mGenericVertexAttribTypeInvalidator.InvalidateCaches();
if (!index) {
const int32_t data[4] = { x, y, z, w };
@ -144,6 +146,7 @@ WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLui
////
mGenericVertexAttribTypes[index] = LOCAL_GL_UNSIGNED_INT;
mGenericVertexAttribTypeInvalidator.InvalidateCaches();
if (!index) {
const uint32_t data[4] = { x, y, z, w };
@ -163,12 +166,12 @@ WebGLContext::EnableVertexAttribArray(GLuint index)
return;
MakeContextCurrent();
InvalidateBufferFetching();
gl->fEnableVertexAttribArray(index);
MOZ_ASSERT(mBoundVertexArray);
mBoundVertexArray->mAttribs[index].mEnabled = true;
mBoundVertexArray->InvalidateCaches();
}
void
@ -181,7 +184,6 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
return;
MakeContextCurrent();
InvalidateBufferFetching();
if (index || !gl->IsCompatibilityProfile()) {
gl->fDisableVertexAttribArray(index);
@ -189,6 +191,7 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
MOZ_ASSERT(mBoundVertexArray);
mBoundVertexArray->mAttribs[index].mEnabled = false;
mBoundVertexArray->InvalidateCaches();
}
JS::Value
@ -425,8 +428,7 @@ WebGLContext::VertexAttribAnyPointer(const char* funcName, bool isFuncInt, GLuin
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
vd.VertexAttribPointer(isFuncInt, buffer, size, type, normalized, stride, byteOffset);
InvalidateBufferFetching();
mBoundVertexArray->InvalidateCaches();
}
////////////////////////////////////////
@ -441,11 +443,8 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
return;
MOZ_ASSERT(mBoundVertexArray);
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
vd.mDivisor = divisor;
InvalidateBufferFetching();
mBoundVertexArray->mAttribs[index].mDivisor = divisor;
mBoundVertexArray->InvalidateCaches();
MakeContextCurrent();

Просмотреть файл

@ -12,11 +12,13 @@
#include "mozilla/RefPtr.h"
#include "nsPrintfCString.h"
#include "WebGLActiveInfo.h"
#include "WebGLBuffer.h"
#include "WebGLContext.h"
#include "WebGLShader.h"
#include "WebGLTransformFeedback.h"
#include "WebGLUniformLocation.h"
#include "WebGLValidateStrings.h"
#include "WebGLVertexArray.h"
namespace mozilla {
@ -264,6 +266,10 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
const GLenum baseType = AttribBaseType(elemType);
const webgl::AttribInfo attrib = {activeInfo, loc, baseType};
info->attribs.push_back(attrib);
if (loc == 0) {
info->attrib0Active = true;
}
}
// Uniforms (can be basically anything)
@ -443,6 +449,7 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
: prog(prog)
, transformFeedbackBufferMode(prog->mNextLink_TransformFeedbackBufferMode)
, attrib0Active(false)
{ }
webgl::LinkedProgramInfo::~LinkedProgramInfo()
@ -455,6 +462,101 @@ webgl::LinkedProgramInfo::~LinkedProgramInfo()
}
}
const webgl::CachedDrawFetchLimits*
webgl::LinkedProgramInfo::GetDrawFetchLimits(const char* const funcName) const
{
const auto& webgl = prog->mContext;
const auto& vao = webgl->mBoundVertexArray;
const auto found = mDrawFetchCache.Find(vao);
if (found)
return found;
std::vector<const CacheMapInvalidator*> cacheDeps;
cacheDeps.push_back(vao.get());
cacheDeps.push_back(&webgl->mGenericVertexAttribTypeInvalidator);
{
// We have to ensure that every enabled attrib array (not just the active ones)
// has a non-null buffer.
uint32_t i = 0;
for (const auto& cur : vao->mAttribs) {
if (cur.mEnabled && !cur.mBuf) {
webgl->ErrorInvalidOperation("%s: Vertex attrib array %u is enabled but"
" has no buffer bound.",
funcName, i);
return nullptr;
}
}
}
bool hasActiveAttrib = false;
bool hasActiveDivisor0 = false;
webgl::CachedDrawFetchLimits fetchLimits = { UINT64_MAX, UINT64_MAX };
for (const auto& progAttrib : this->attribs) {
const auto& loc = progAttrib.mLoc;
if (loc == -1)
continue;
hasActiveAttrib |= true;
const auto& attribData = vao->mAttribs[loc];
hasActiveDivisor0 |= (attribData.mDivisor == 0);
GLenum attribDataBaseType;
if (attribData.mEnabled) {
MOZ_ASSERT(attribData.mBuf);
if (attribData.mBuf->IsBoundForTF()) {
webgl->ErrorInvalidOperation("%s: Vertex attrib %u's buffer is bound for"
" transform feedback.",
funcName, loc);
return nullptr;
}
cacheDeps.push_back(&attribData.mBuf->mFetchInvalidator);
attribDataBaseType = attribData.BaseType();
const size_t availBytes = attribData.mBuf->ByteLength();
const auto availElems = AvailGroups(availBytes, attribData.ByteOffset(),
attribData.BytesPerVertex(),
attribData.ExplicitStride());
if (attribData.mDivisor) {
const auto availInstances = CheckedInt<uint64_t>(availElems) * attribData.mDivisor;
if (availInstances.isValid()) {
fetchLimits.maxInstances = std::min(fetchLimits.maxInstances,
availInstances.value());
} // If not valid, it overflowed too large, so we're super safe.
} else {
fetchLimits.maxVerts = std::min(fetchLimits.maxVerts, availElems);
}
} else {
attribDataBaseType = webgl->mGenericVertexAttribTypes[loc];
}
if (attribDataBaseType != progAttrib.mBaseType) {
nsCString progType, dataType;
WebGLContext::EnumName(progAttrib.mBaseType, &progType);
WebGLContext::EnumName(attribDataBaseType, &dataType);
webgl->ErrorInvalidOperation("%s: Vertex attrib %u requires data of type %s,"
" but is being supplied with type %s.",
funcName, loc, progType.BeginReading(),
dataType.BeginReading());
return nullptr;
}
}
if (hasActiveAttrib && !hasActiveDivisor0) {
webgl->ErrorInvalidOperation("%s: One active vertex attrib (if any are active)"
" must have a divisor of 0.",
funcName);
return nullptr;
}
// --
return mDrawFetchCache.Insert(vao.get(), Move(fetchLimits), Move(cacheDeps));
}
////////////////////////////////////////////////////////////////////////////////
// WebGLProgram
@ -1069,7 +1171,6 @@ WebGLProgram::LinkProgram()
}
mContext->MakeContextCurrent();
mContext->InvalidateBufferFetching(); // we do it early in this function
// as some of the validation changes program state
mLinkLog.Truncate();
@ -1365,8 +1466,6 @@ WebGLProgram::UseProgram() const
mContext->MakeContextCurrent();
mContext->InvalidateBufferFetching();
mContext->gl->fUseProgram(mGLName);
return true;
}

Просмотреть файл

@ -17,6 +17,7 @@
#include "nsString.h"
#include "nsWrapperCache.h"
#include "CacheMap.h"
#include "WebGLContext.h"
#include "WebGLObjectModel.h"
@ -75,6 +76,11 @@ struct UniformBlockInfo final
{ }
};
struct CachedDrawFetchLimits final {
uint64_t maxVerts;
uint64_t maxInstances;
};
struct LinkedProgramInfo final
: public RefCounted<LinkedProgramInfo>
, public SupportsWeakPtr<LinkedProgramInfo>
@ -99,11 +105,22 @@ struct LinkedProgramInfo final
mutable std::vector<size_t> componentsPerTFVert;
bool attrib0Active;
//////
// The maps for the frag data names to the translated names.
std::map<nsCString, const nsCString> fragDataMap;
//////
mutable CacheMap<const WebGLVertexArray*,
CachedDrawFetchLimits> mDrawFetchCache;
const CachedDrawFetchLimits* GetDrawFetchLimits(const char* funcName) const;
//////
explicit LinkedProgramInfo(WebGLProgram* prog);
~LinkedProgramInfo();

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
#include "CacheMap.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
#include "WebGLVertexAttribData.h"
@ -17,11 +18,15 @@
namespace mozilla {
class WebGLVertexArrayFake;
namespace webgl {
struct LinkedProgramInfo;
}
class WebGLVertexArray
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLVertexArray>
, public LinkedListElement<WebGLVertexArray>
, public CacheMapInvalidator
{
public:
static WebGLVertexArray* Create(WebGLContext* webgl);
@ -66,6 +71,7 @@ protected:
friend class WebGLContext;
friend class WebGLVertexArrayFake;
friend class WebGL2Context;
friend struct webgl::LinkedProgramInfo;
};
} // namespace mozilla