зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1404196 - Simplify and repair vertex fetch. - r=daoshengmu
MozReview-Commit-ID: FL7uibuv4VY
This commit is contained in:
Родитель
cebb6665ed
Коммит
d6af1e81ba
|
@ -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, ¤tProgram);
|
||||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче