bug 900767 - Implement the WebGL extension ANGLE_instanced_arrays - r=jgilbert

This commit is contained in:
Guillaume Abadie 2013-08-13 18:11:01 -04:00
parent e5911a1739
commit 25894203e2
9 changed files with 146 additions and 22 deletions

View File

@ -197,9 +197,7 @@ WebGLContext::WebGLContext()
mLastUseIndex = 0;
mBufferFetchingIsVerified = false;
mMaxFetchedVertices = 0;
mMaxFetchedInstances = 0;
InvalidateBufferFetching();
mIsScreenCleared = false;
@ -1019,6 +1017,8 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
return true;
}
return false;
case ANGLE_instanced_arrays:
return WebGLExtensionInstancedArrays::IsSupported(this);
default:
// For warnings-as-errors.
break;
@ -1118,6 +1118,10 @@ WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& r
{
ext = WEBGL_draw_buffers;
}
else if (CompareWebGLExtensionName(name, "ANGLE_instanced_arrays"))
{
ext = ANGLE_instanced_arrays;
}
if (ext == WebGLExtensionID_unknown_extension) {
return nullptr;
@ -1184,6 +1188,9 @@ WebGLContext::EnableExtension(WebGLExtensionID ext)
case OES_vertex_array_object:
obj = new WebGLExtensionVertexArray(this);
break;
case ANGLE_instanced_arrays:
obj = new WebGLExtensionInstancedArrays(this);
break;
default:
MOZ_ASSERT(false, "should not get there.");
}
@ -1592,6 +1599,8 @@ WebGLContext::GetSupportedExtensions(JSContext *cx, Nullable< nsTArray<nsString>
arr.AppendElement(NS_LITERAL_STRING("WEBGL_draw_buffers"));
if (IsExtensionSupported(cx, OES_vertex_array_object))
arr.AppendElement(NS_LITERAL_STRING("OES_vertex_array_object"));
if (IsExtensionSupported(cx, ANGLE_instanced_arrays))
arr.AppendElement(NS_LITERAL_STRING("ANGLE_instanced_arrays"));
}
//

View File

@ -815,6 +815,21 @@ public:
void VertexAttribDivisor(WebGLuint index, WebGLuint 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;
inline void InvalidateBufferFetching()
{
mBufferFetchingIsVerified = false;
mBufferFetchingHasPerVertex = false;
mMaxFetchedVertices = 0;
mMaxFetchedInstances = 0;
}
bool DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei primcount, const char* info);
bool DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr byteOffset,
WebGLsizei primcount, const char* info);
@ -895,19 +910,6 @@ protected:
int32_t mGLMaxColorAttachments;
int32_t mGLMaxDrawBuffers;
// Cache the max number of vertices and isntances that can be read from
// bound VBOs (result of ValidateBuffers).
bool mBufferFetchingIsVerified;
uint32_t mMaxFetchedVertices;
uint32_t mMaxFetchedInstances;
inline void InvalidateBufferFetching()
{
mBufferFetchingIsVerified = false;
mMaxFetchedVertices = 0;
mMaxFetchedInstances = 0;
}
// Represents current status, or state, of the context. That is, is it lost
// or stable and what part of the context lost process are we currently at.
// This is used to support the WebGL spec's asyncronous nature in handling
@ -942,6 +944,7 @@ protected:
WEBGL_depth_texture,
WEBGL_lose_context,
WEBGL_draw_buffers,
ANGLE_instanced_arrays,
WebGLExtensionID_unknown_extension
};
nsTArray<nsRefPtr<WebGLExtensionBase> > mExtensions;

View File

@ -995,10 +995,9 @@ WebGLContext::InitAndValidateGL()
if (IsWebGL2() &&
(!IsExtensionSupported(OES_vertex_array_object) ||
!IsExtensionSupported(WEBGL_draw_buffers) ||
!IsExtensionSupported(ANGLE_instanced_arrays) ||
!gl->IsExtensionSupported(gl::GLContext::EXT_gpu_shader4) ||
!gl->IsExtensionSupported(gl::GLContext::EXT_blend_minmax) ||
!gl->IsExtensionSupported(gl::GLContext::XXX_draw_instanced) ||
!gl->IsExtensionSupported(gl::GLContext::XXX_instanced_arrays) ||
(gl->IsGLES2() && !gl->IsExtensionSupported(gl::GLContext::EXT_occlusion_query_boolean))
))
{
@ -1023,9 +1022,11 @@ WebGLContext::InitAndValidateGL()
if (IsWebGL2()) {
EnableExtension(OES_vertex_array_object);
EnableExtension(WEBGL_draw_buffers);
EnableExtension(ANGLE_instanced_arrays);
MOZ_ASSERT(IsExtensionEnabled(OES_vertex_array_object));
MOZ_ASSERT(IsExtensionEnabled(WEBGL_draw_buffers));
MOZ_ASSERT(IsExtensionEnabled(ANGLE_instanced_arrays));
}
return true;

View File

@ -262,7 +262,7 @@ WebGLContext::GetVertexAttrib(JSContext* cx, WebGLuint index, WebGLenum pname,
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
{
if (IsWebGL2())
if (IsExtensionEnabled(ANGLE_instanced_arrays))
{
return JS::Int32Value(mBoundVertexArray->mAttribBuffers[index].divisor);
}
@ -470,6 +470,16 @@ bool WebGLContext::DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei
return false;
}
if (!mBufferFetchingHasPerVertex && !IsWebGL2()) {
/* 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.
*/
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
@ -624,6 +634,16 @@ WebGLContext::DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr b
return false;
}
if (!mBufferFetchingHasPerVertex && !IsWebGL2()) {
/* 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.
*/
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
@ -674,7 +694,7 @@ WebGLContext::DrawElementsInstanced(WebGLenum mode, WebGLsizei count, WebGLenum
return;
SetupContextLossTimer();
gl->fDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset));
gl->fDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(byteOffset), primcount);
Draw_cleanup();
}
@ -722,6 +742,7 @@ WebGLContext::ValidateBufferFetching(const char *info)
return true;
}
bool hasPerVertex = false;
uint32_t maxVertices = UINT32_MAX;
uint32_t maxInstances = UINT32_MAX;
uint32_t attribs = mBoundVertexArray->mAttribBuffers.Length();
@ -768,13 +789,16 @@ WebGLContext::ValidateBufferFetching(const char *info)
return false;
}
if (vd.divisor == 0)
if (vd.divisor == 0) {
maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
else
hasPerVertex = true;
} else {
maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
}
}
mBufferFetchingIsVerified = true;
mBufferFetchingHasPerVertex = hasPerVertex;
mMaxFetchedVertices = maxVertices;
mMaxFetchedInstances = maxInstances;

View File

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLContext.h"
#include "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
using namespace mozilla;
WebGLExtensionInstancedArrays::WebGLExtensionInstancedArrays(WebGLContext* context)
: WebGLExtensionBase(context)
{
MOZ_ASSERT(IsSupported(context), "should not construct WebGLExtensionInstancedArrays: "
"ANGLE_instanced_arrays unsupported.");
}
WebGLExtensionInstancedArrays::~WebGLExtensionInstancedArrays()
{
}
void
WebGLExtensionInstancedArrays::DrawArraysInstancedANGLE(WebGLenum mode, WebGLint first,
WebGLsizei count, WebGLsizei primcount)
{
mContext->DrawArraysInstanced(mode, first, count, primcount);
}
void
WebGLExtensionInstancedArrays::DrawElementsInstancedANGLE(WebGLenum mode, WebGLsizei count,
WebGLenum type, WebGLintptr offset,
WebGLsizei primcount)
{
mContext->DrawElementsInstanced(mode, count, type, offset, primcount);
}
void
WebGLExtensionInstancedArrays::VertexAttribDivisorANGLE(WebGLuint index, WebGLuint divisor)
{
mContext->VertexAttribDivisor(index, divisor);
}
bool
WebGLExtensionInstancedArrays::IsSupported(const WebGLContext* context)
{
gl::GLContext* gl = context->GL();
return gl->IsExtensionSupported(gl::GLContext::XXX_draw_instanced) &&
gl->IsExtensionSupported(gl::GLContext::XXX_instanced_arrays);
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionInstancedArrays)

View File

@ -189,6 +189,25 @@ public:
DECL_WEBGL_EXTENSION_GOOP
};
class WebGLExtensionInstancedArrays
: public WebGLExtensionBase
{
public:
WebGLExtensionInstancedArrays(WebGLContext* context);
virtual ~WebGLExtensionInstancedArrays();
void DrawArraysInstancedANGLE(WebGLenum mode, WebGLint first,
WebGLsizei count, WebGLsizei primcount);
void DrawElementsInstancedANGLE(WebGLenum mode, WebGLsizei count,
WebGLenum type, WebGLintptr offset,
WebGLsizei primcount);
void VertexAttribDivisorANGLE(WebGLuint index, WebGLuint divisor);
static bool IsSupported(const WebGLContext* context);
DECL_WEBGL_EXTENSION_GOOP
};
} // namespace mozilla
#endif // WEBGLEXTENSIONS_H_

View File

@ -48,6 +48,7 @@ if CONFIG['MOZ_WEBGL']:
'WebGLExtensionDepthTexture.cpp',
'WebGLExtensionDrawBuffers.cpp',
'WebGLExtensionElementIndexUint.cpp',
'WebGLExtensionInstancedArrays.cpp',
'WebGLExtensionLoseContext.cpp',
'WebGLExtensionStandardDerivatives.cpp',
'WebGLExtensionTextureFilterAnisotropic.cpp',

View File

@ -1305,6 +1305,11 @@ DOMInterfaces = {
'headerFile': 'WebGLExtensions.h'
},
'WebGLExtensionInstancedArrays': {
'nativeType': 'mozilla::WebGLExtensionInstancedArrays',
'headerFile': 'WebGLExtensions.h'
},
'WebGLFramebuffer': {
'nativeType': 'mozilla::WebGLFramebuffer',
'headerFile': 'WebGLFramebuffer.h'

View File

@ -896,3 +896,12 @@ interface WebGLExtensionVertexArray {
[WebGLHandlesContextLoss] GLboolean isVertexArrayOES(WebGLVertexArray? arrayObject);
void bindVertexArrayOES(WebGLVertexArray? arrayObject);
};
[NoInterfaceObject]
interface WebGLExtensionInstancedArrays {
const GLenum VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x88FE;
void drawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount);
void drawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei primcount);
void vertexAttribDivisorANGLE(GLuint index, GLuint divisor);
};