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
Родитель e5911a1739
Коммит 25894203e2
9 изменённых файлов: 146 добавлений и 22 удалений

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

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

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

@ -815,6 +815,21 @@ public:
void VertexAttribDivisor(WebGLuint index, WebGLuint divisor); void VertexAttribDivisor(WebGLuint index, WebGLuint divisor);
private: 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 DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei primcount, const char* info);
bool DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr byteOffset, bool DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr byteOffset,
WebGLsizei primcount, const char* info); WebGLsizei primcount, const char* info);
@ -895,19 +910,6 @@ protected:
int32_t mGLMaxColorAttachments; int32_t mGLMaxColorAttachments;
int32_t mGLMaxDrawBuffers; 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 // 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. // 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 // This is used to support the WebGL spec's asyncronous nature in handling
@ -942,6 +944,7 @@ protected:
WEBGL_depth_texture, WEBGL_depth_texture,
WEBGL_lose_context, WEBGL_lose_context,
WEBGL_draw_buffers, WEBGL_draw_buffers,
ANGLE_instanced_arrays,
WebGLExtensionID_unknown_extension WebGLExtensionID_unknown_extension
}; };
nsTArray<nsRefPtr<WebGLExtensionBase> > mExtensions; nsTArray<nsRefPtr<WebGLExtensionBase> > mExtensions;

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

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

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

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

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

@ -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)

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

@ -189,6 +189,25 @@ public:
DECL_WEBGL_EXTENSION_GOOP 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 } // namespace mozilla
#endif // WEBGLEXTENSIONS_H_ #endif // WEBGLEXTENSIONS_H_

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

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

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

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

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

@ -896,3 +896,12 @@ interface WebGLExtensionVertexArray {
[WebGLHandlesContextLoss] GLboolean isVertexArrayOES(WebGLVertexArray? arrayObject); [WebGLHandlesContextLoss] GLboolean isVertexArrayOES(WebGLVertexArray? arrayObject);
void bindVertexArrayOES(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);
};