Bug 890379 - [WebGL 2.0] Add existing WebGL 1 extensions as WebGL 2 features. r=jgilbert

This commit is contained in:
Guillaume Abadie 2013-07-17 12:13:38 -04:00
parent 049e48a959
commit 7315912dd4
10 changed files with 491 additions and 371 deletions

View File

@ -958,6 +958,11 @@ bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) con
}
}
return IsExtensionSupported(ext);
}
bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
{
if (mDisableExtensions) {
return false;
}
@ -1123,57 +1128,67 @@ WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& r
// step 3: if the extension hadn't been previously been created, create it now, thus enabling it
if (!IsExtensionEnabled(ext)) {
WebGLExtensionBase *obj = nullptr;
switch (ext) {
case OES_element_index_uint:
obj = new WebGLExtensionElementIndexUint(this);
break;
case OES_standard_derivatives:
obj = new WebGLExtensionStandardDerivatives(this);
break;
case EXT_texture_filter_anisotropic:
obj = new WebGLExtensionTextureFilterAnisotropic(this);
break;
case WEBGL_lose_context:
obj = new WebGLExtensionLoseContext(this);
break;
case WEBGL_compressed_texture_s3tc:
obj = new WebGLExtensionCompressedTextureS3TC(this);
break;
case WEBGL_compressed_texture_atc:
obj = new WebGLExtensionCompressedTextureATC(this);
break;
case WEBGL_compressed_texture_pvrtc:
obj = new WebGLExtensionCompressedTexturePVRTC(this);
break;
case WEBGL_debug_renderer_info:
obj = new WebGLExtensionDebugRendererInfo(this);
break;
case WEBGL_depth_texture:
obj = new WebGLExtensionDepthTexture(this);
break;
case OES_texture_float:
obj = new WebGLExtensionTextureFloat(this);
break;
case OES_texture_float_linear:
obj = new WebGLExtensionTextureFloatLinear(this);
break;
case WEBGL_draw_buffers:
obj = new WebGLExtensionDrawBuffers(this);
break;
case OES_vertex_array_object:
obj = new WebGLExtensionVertexArray(this);
break;
default:
MOZ_ASSERT(false, "should not get there.");
}
mExtensions.EnsureLengthAtLeast(ext + 1);
mExtensions[ext] = obj;
EnableExtension(ext);
}
return WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv);
}
void
WebGLContext::EnableExtension(WebGLExtensionID ext)
{
mExtensions.EnsureLengthAtLeast(ext + 1);
MOZ_ASSERT(IsExtensionEnabled(ext) == false);
WebGLExtensionBase* obj = nullptr;
switch (ext) {
case OES_element_index_uint:
obj = new WebGLExtensionElementIndexUint(this);
break;
case OES_standard_derivatives:
obj = new WebGLExtensionStandardDerivatives(this);
break;
case EXT_texture_filter_anisotropic:
obj = new WebGLExtensionTextureFilterAnisotropic(this);
break;
case WEBGL_lose_context:
obj = new WebGLExtensionLoseContext(this);
break;
case WEBGL_compressed_texture_s3tc:
obj = new WebGLExtensionCompressedTextureS3TC(this);
break;
case WEBGL_compressed_texture_atc:
obj = new WebGLExtensionCompressedTextureATC(this);
break;
case WEBGL_compressed_texture_pvrtc:
obj = new WebGLExtensionCompressedTexturePVRTC(this);
break;
case WEBGL_debug_renderer_info:
obj = new WebGLExtensionDebugRendererInfo(this);
break;
case WEBGL_depth_texture:
obj = new WebGLExtensionDepthTexture(this);
break;
case OES_texture_float:
obj = new WebGLExtensionTextureFloat(this);
break;
case OES_texture_float_linear:
obj = new WebGLExtensionTextureFloatLinear(this);
break;
case WEBGL_draw_buffers:
obj = new WebGLExtensionDrawBuffers(this);
break;
case OES_vertex_array_object:
obj = new WebGLExtensionVertexArray(this);
break;
default:
MOZ_ASSERT(false, "should not get there.");
}
mExtensions[ext] = obj;
}
void
WebGLContext::ClearScreen()
{

View File

@ -390,6 +390,7 @@ public:
void DrawArrays(GLenum mode, WebGLint first, WebGLsizei count);
void DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
WebGLintptr byteOffset);
void DrawBuffers(const dom::Sequence<GLenum>& buffers);
void Enable(WebGLenum cap);
void EnableVertexAttribArray(WebGLuint index);
void Flush() {
@ -894,11 +895,15 @@ protected:
};
nsTArray<nsRefPtr<WebGLExtensionBase> > mExtensions;
// enable an extension. the extension should not be enabled before.
void EnableExtension(WebGLExtensionID ext);
// returns true if the extension has been enabled by calling getExtension.
bool IsExtensionEnabled(WebGLExtensionID ext) const;
// returns true if the extension is supported for this JSContext (this decides what getSupportedExtensions exposes)
bool IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const;
bool IsExtensionSupported(WebGLExtensionID ext) const;
nsTArray<WebGLenum> mCompressedTextureFormats;

View File

@ -0,0 +1,264 @@
/* -*- Mode: C++; tab-width: 4; 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 "WebGLTexture.h"
#include "WebGLRenderbuffer.h"
#include "WebGLFramebuffer.h"
using namespace mozilla;
void
WebGLContext::Clear(WebGLbitfield mask)
{
if (!IsContextStable())
return;
MakeContextCurrent();
uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
if (mask != m)
return ErrorInvalidValue("clear: invalid mask bits");
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
gl->fClear(mask);
return;
}
// Ok, we're clearing the default framebuffer/screen.
bool needsClear = true;
if (mIsScreenCleared) {
bool isClearRedundant = true;
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
if (mColorClearValue[0] != 0.0f ||
mColorClearValue[1] != 0.0f ||
mColorClearValue[2] != 0.0f ||
mColorClearValue[3] != 0.0f)
{
isClearRedundant = false;
}
}
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
if (mDepthClearValue != 1.0f) {
isClearRedundant = false;
}
}
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
if (mStencilClearValue != 0) {
isClearRedundant = false;
}
}
if (isClearRedundant)
needsClear = false;
}
if (needsClear) {
gl->fClear(mask);
mIsScreenCleared = false;
}
Invalidate();
mShouldPresent = true;
}
static WebGLclampf
GLClampFloat(WebGLclampf val)
{
if (val < 0.0)
return 0.0;
if (val > 1.0)
return 1.0;
return val;
}
void
WebGLContext::ClearColor(WebGLclampf r, WebGLclampf g,
WebGLclampf b, WebGLclampf a)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mColorClearValue[0] = GLClampFloat(r);
mColorClearValue[1] = GLClampFloat(g);
mColorClearValue[2] = GLClampFloat(b);
mColorClearValue[3] = GLClampFloat(a);
gl->fClearColor(r, g, b, a);
}
void
WebGLContext::ClearDepth(WebGLclampf v)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mDepthClearValue = GLClampFloat(v);
gl->fClearDepth(v);
}
void
WebGLContext::ClearStencil(WebGLint v)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mStencilClearValue = v;
gl->fClearStencil(v);
}
void
WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mColorWriteMask[0] = r;
mColorWriteMask[1] = g;
mColorWriteMask[2] = b;
mColorWriteMask[3] = a;
gl->fColorMask(r, g, b, a);
}
void
WebGLContext::DepthMask(WebGLboolean b)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mDepthWriteMask = b;
gl->fDepthMask(b);
}
void
WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
{
const size_t buffersLength = buffers.Length();
if (buffersLength == 0) {
return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers must not be empty)");
}
if (mBoundFramebuffer == 0)
{
// OK: we are rendering in the default framebuffer
/* EXT_draw_buffers :
If the GL is bound to the default framebuffer, then <buffersLength> must be 1
and the constant must be BACK or NONE. When draw buffer zero is
BACK, color values are written into the sole buffer for single-
buffered contexts, or into the back buffer for double-buffered
contexts. If DrawBuffersEXT is supplied with a constant other than
BACK and NONE, the error INVALID_OPERATION is generated.
*/
if (buffersLength != 1) {
return ErrorInvalidValue("drawBuffers: invalid <buffers> (main framebuffer: buffers.length must be 1)");
}
MakeContextCurrent();
if (buffers[0] == LOCAL_GL_NONE) {
const GLenum drawBuffersCommand = LOCAL_GL_NONE;
gl->fDrawBuffers(1, &drawBuffersCommand);
return;
}
else if (buffers[0] == LOCAL_GL_BACK) {
const GLenum drawBuffersCommand = LOCAL_GL_COLOR_ATTACHMENT0;
gl->fDrawBuffers(1, &drawBuffersCommand);
return;
}
return ErrorInvalidOperation("drawBuffers: invalid operation (main framebuffer: buffers[0] must be GL_NONE or GL_BACK)");
}
// OK: we are rendering in a framebuffer object
if (buffersLength > size_t(mGLMaxDrawBuffers)) {
/* EXT_draw_buffers :
The maximum number of draw buffers is implementation-dependent. The
number of draw buffers supported can be queried by calling
GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An
INVALID_VALUE error is generated if <buffersLength> is greater than
MAX_DRAW_BUFFERS_EXT.
*/
return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers.length > GL_MAX_DRAW_BUFFERS)");
}
for (uint32_t i = 0; i < buffersLength; i++)
{
/* EXT_draw_buffers :
If the GL is bound to a draw framebuffer object, the <i>th buffer listed
in <bufs> must be COLOR_ATTACHMENT<i>_EXT or NONE. Specifying a
buffer out of order, BACK, or COLOR_ATTACHMENT<m>_EXT where <m> is
greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT,
will generate the error INVALID_OPERATION.
*/
/* WEBGL_draw_buffers :
The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter.
*/
if (buffers[i] != LOCAL_GL_NONE &&
buffers[i] != GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + i)) {
return ErrorInvalidOperation("drawBuffers: invalid operation (buffers[i] must be GL_NONE or GL_COLOR_ATTACHMENTi)");
}
}
MakeContextCurrent();
gl->fDrawBuffers(buffersLength, buffers.Elements());
}
void
WebGLContext::StencilMask(WebGLuint mask)
{
if (!IsContextStable())
return;
mStencilWriteMaskFront = mask;
mStencilWriteMaskBack = mask;
MakeContextCurrent();
gl->fStencilMask(mask);
}
void
WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask)
{
if (!IsContextStable())
return;
if (!ValidateFaceEnum(face, "stencilMaskSeparate: face"))
return;
switch (face) {
case LOCAL_GL_FRONT_AND_BACK:
mStencilWriteMaskFront = mask;
mStencilWriteMaskBack = mask;
break;
case LOCAL_GL_FRONT:
mStencilWriteMaskFront = mask;
break;
case LOCAL_GL_BACK:
mStencilWriteMaskBack = mask;
break;
}
MakeContextCurrent();
gl->fStencilMaskSeparate(face, mask);
}

View File

@ -227,39 +227,6 @@ WebGLContext::BindRenderbuffer(WebGLenum target, WebGLRenderbuffer *wrb)
mBoundRenderbuffer = wrb;
}
void
WebGLContext::BindVertexArray(WebGLVertexArray *array)
{
if (!IsContextStable())
return;
if (!ValidateObjectAllowDeletedOrNull("bindVertexArrayObject", array))
return;
if (array && array->IsDeleted()) {
/* http://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt
* BindVertexArrayOES fails and an INVALID_OPERATION error is
* generated if array is not a name returned from a previous call to
* GenVertexArraysOES, or if such a name has since been deleted with
* DeleteVertexArraysOES
*/
ErrorInvalidOperation("bindVertexArray: can't bind a deleted array!");
return;
}
MakeContextCurrent();
if (array) {
gl->fBindVertexArray(array->GLName());
array->SetHasEverBeenBound(true);
mBoundVertexArray = array;
}
else {
gl->fBindVertexArray(0);
mBoundVertexArray = mDefaultVertexArray;
}
}
void
WebGLContext::BindTexture(WebGLenum target, WebGLTexture *tex)
{
@ -645,129 +612,6 @@ WebGLContext::CheckFramebufferStatus(WebGLenum target)
return gl->fCheckFramebufferStatus(target);
}
void
WebGLContext::Clear(WebGLbitfield mask)
{
if (!IsContextStable())
return;
MakeContextCurrent();
uint32_t m = mask & (LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT | LOCAL_GL_STENCIL_BUFFER_BIT);
if (mask != m)
return ErrorInvalidValue("clear: invalid mask bits");
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
gl->fClear(mask);
return;
}
// Ok, we're clearing the default framebuffer/screen.
bool needsClear = true;
if (mIsScreenCleared) {
bool isClearRedundant = true;
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
if (mColorClearValue[0] != 0.0f ||
mColorClearValue[1] != 0.0f ||
mColorClearValue[2] != 0.0f ||
mColorClearValue[3] != 0.0f)
{
isClearRedundant = false;
}
}
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
if (mDepthClearValue != 1.0f) {
isClearRedundant = false;
}
}
if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
if (mStencilClearValue != 0) {
isClearRedundant = false;
}
}
if (isClearRedundant)
needsClear = false;
}
if (needsClear) {
gl->fClear(mask);
mIsScreenCleared = false;
}
Invalidate();
mShouldPresent = true;
}
static WebGLclampf
GLClampFloat(WebGLclampf val)
{
if (val < 0.0)
return 0.0;
if (val > 1.0)
return 1.0;
return val;
}
void
WebGLContext::ClearColor(WebGLclampf r, WebGLclampf g,
WebGLclampf b, WebGLclampf a)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mColorClearValue[0] = GLClampFloat(r);
mColorClearValue[1] = GLClampFloat(g);
mColorClearValue[2] = GLClampFloat(b);
mColorClearValue[3] = GLClampFloat(a);
gl->fClearColor(r, g, b, a);
}
void
WebGLContext::ClearDepth(WebGLclampf v)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mDepthClearValue = GLClampFloat(v);
gl->fClearDepth(v);
}
void
WebGLContext::ClearStencil(WebGLint v)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mStencilClearValue = v;
gl->fClearStencil(v);
}
void
WebGLContext::ColorMask(WebGLboolean r, WebGLboolean g, WebGLboolean b, WebGLboolean a)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mColorWriteMask[0] = r;
mColorWriteMask[1] = g;
mColorWriteMask[2] = b;
mColorWriteMask[3] = a;
gl->fColorMask(r, g, b, a);
}
void
WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
WebGLint level,
@ -1165,24 +1009,6 @@ WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer *rbuf)
rbuf->RequestDelete();
}
void
WebGLContext::DeleteVertexArray(WebGLVertexArray *array)
{
if (!IsContextStable())
return;
if (array == nullptr)
return;
if (array->IsDeleted())
return;
if (mBoundVertexArray == array)
BindVertexArray(static_cast<WebGLVertexArray*>(nullptr));
array->RequestDelete();
}
void
WebGLContext::DeleteTexture(WebGLTexture *tex)
{
@ -1271,17 +1097,6 @@ WebGLContext::DepthFunc(WebGLenum func)
gl->fDepthFunc(func);
}
void
WebGLContext::DepthMask(WebGLboolean b)
{
if (!IsContextStable())
return;
MakeContextCurrent();
mDepthWriteMask = b;
gl->fDepthMask(b);
}
void
WebGLContext::DepthRange(WebGLfloat zNear, WebGLfloat zFar)
{
@ -3192,20 +3007,6 @@ WebGLContext::IsRenderbuffer(WebGLRenderbuffer *rb)
rb->HasEverBeenBound();
}
bool
WebGLContext::IsVertexArray(WebGLVertexArray *array)
{
if (!IsContextStable())
return false;
if (!array)
return false;
return ValidateObjectAllowDeleted("isVertexArray", array) &&
!array->IsDeleted() &&
array->HasEverBeenBound();
}
bool
WebGLContext::IsShader(WebGLShader *shader)
{
@ -3759,45 +3560,6 @@ WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref,
gl->fStencilFuncSeparate(face, func, ref, mask);
}
void
WebGLContext::StencilMask(WebGLuint mask)
{
if (!IsContextStable())
return;
mStencilWriteMaskFront = mask;
mStencilWriteMaskBack = mask;
MakeContextCurrent();
gl->fStencilMask(mask);
}
void
WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask)
{
if (!IsContextStable())
return;
if (!ValidateFaceEnum(face, "stencilMaskSeparate: face"))
return;
switch (face) {
case LOCAL_GL_FRONT_AND_BACK:
mStencilWriteMaskFront = mask;
mStencilWriteMaskBack = mask;
break;
case LOCAL_GL_FRONT:
mStencilWriteMaskFront = mask;
break;
case LOCAL_GL_BACK:
mStencilWriteMaskBack = mask;
break;
}
MakeContextCurrent();
gl->fStencilMaskSeparate(face, mask);
}
void
WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
{
@ -4427,22 +4189,6 @@ WebGLContext::CreateRenderbuffer()
return globj.forget();
}
already_AddRefed<WebGLVertexArray>
WebGLContext::CreateVertexArray()
{
if (!IsContextStable())
return nullptr;
nsRefPtr<WebGLVertexArray> globj = new WebGLVertexArray(this);
MakeContextCurrent();
gl->fGenVertexArrays(1, &globj->mGLName);
mVertexArrays.insertBack(globj);
return globj.forget();
}
void
WebGLContext::Viewport(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
{

View File

@ -1049,6 +1049,14 @@ WebGLContext::InitAndValidateGL()
return false;
}
if (IsWebGL2() &&
(!IsExtensionSupported(OES_vertex_array_object) ||
!IsExtensionSupported(WEBGL_draw_buffers)
))
{
return false;
}
mMemoryPressureObserver
= new WebGLMemoryPressureObserver(this);
nsCOMPtr<nsIObserverService> observerService
@ -1063,5 +1071,13 @@ WebGLContext::InitAndValidateGL()
mDefaultVertexArray->mAttribBuffers.SetLength(mGLMaxVertexAttribs);
mBoundVertexArray = mDefaultVertexArray;
if (IsWebGL2()) {
EnableExtension(OES_vertex_array_object);
EnableExtension(WEBGL_draw_buffers);
MOZ_ASSERT(IsExtensionEnabled(OES_vertex_array_object));
MOZ_ASSERT(IsExtensionEnabled(WEBGL_draw_buffers));
}
return true;
}

View File

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 4; 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 "WebGLBuffer.h"
#include "WebGLVertexAttribData.h"
#include "WebGLVertexArray.h"
using namespace mozilla;
void
WebGLContext::BindVertexArray(WebGLVertexArray *array)
{
if (!IsContextStable())
return;
if (!ValidateObjectAllowDeletedOrNull("bindVertexArrayObject", array))
return;
if (array && array->IsDeleted()) {
/* http://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt
* BindVertexArrayOES fails and an INVALID_OPERATION error is
* generated if array is not a name returned from a previous call to
* GenVertexArraysOES, or if such a name has since been deleted with
* DeleteVertexArraysOES
*/
ErrorInvalidOperation("bindVertexArray: can't bind a deleted array!");
return;
}
MakeContextCurrent();
if (array) {
gl->fBindVertexArray(array->GLName());
array->SetHasEverBeenBound(true);
mBoundVertexArray = array;
}
else {
gl->fBindVertexArray(0);
mBoundVertexArray = mDefaultVertexArray;
}
}
already_AddRefed<WebGLVertexArray>
WebGLContext::CreateVertexArray()
{
if (!IsContextStable())
return nullptr;
nsRefPtr<WebGLVertexArray> globj = new WebGLVertexArray(this);
MakeContextCurrent();
gl->fGenVertexArrays(1, &globj->mGLName);
mVertexArrays.insertBack(globj);
return globj.forget();
}
void
WebGLContext::DeleteVertexArray(WebGLVertexArray *array)
{
if (!IsContextStable())
return;
if (array == nullptr)
return;
if (array->IsDeleted())
return;
if (mBoundVertexArray == array)
BindVertexArray(static_cast<WebGLVertexArray*>(nullptr));
array->RequestDelete();
}
bool
WebGLContext::IsVertexArray(WebGLVertexArray *array)
{
if (!IsContextStable())
return false;
if (!array)
return false;
return ValidateObjectAllowDeleted("isVertexArray", array) &&
!array->IsDeleted() &&
array->HasEverBeenBound();
}

View File

@ -48,77 +48,7 @@ WebGLExtensionDrawBuffers::~WebGLExtensionDrawBuffers()
void WebGLExtensionDrawBuffers::DrawBuffersWEBGL(const dom::Sequence<GLenum>& buffers)
{
const size_t buffersLength = buffers.Length();
if (buffersLength == 0) {
return mContext->ErrorInvalidValue("drawBuffersWEBGL: invalid <buffers> (buffers must not be empty)");
}
if (mContext->mBoundFramebuffer == 0)
{
// OK: we are rendering in the default framebuffer
/* EXT_draw_buffers :
If the GL is bound to the default framebuffer, then <buffersLength> must be 1
and the constant must be BACK or NONE. When draw buffer zero is
BACK, color values are written into the sole buffer for single-
buffered contexts, or into the back buffer for double-buffered
contexts. If DrawBuffersEXT is supplied with a constant other than
BACK and NONE, the error INVALID_OPERATION is generated.
*/
if (buffersLength != 1) {
return mContext->ErrorInvalidValue("drawBuffersWEBGL: invalid <buffers> (main framebuffer: buffers.length must be 1)");
}
mContext->MakeContextCurrent();
if (buffers[0] == LOCAL_GL_NONE) {
const GLenum drawBufffersCommand = LOCAL_GL_NONE;
mContext->GL()->fDrawBuffers(1, &drawBufffersCommand);
return;
}
else if (buffers[0] == LOCAL_GL_BACK) {
const GLenum drawBufffersCommand = LOCAL_GL_COLOR_ATTACHMENT0;
mContext->GL()->fDrawBuffers(1, &drawBufffersCommand);
return;
}
return mContext->ErrorInvalidOperation("drawBuffersWEBGL: invalid operation (main framebuffer: buffers[0] must be GL_NONE or GL_BACK)");
}
// OK: we are rendering in a framebuffer object
if (buffersLength > size_t(mContext->mGLMaxDrawBuffers)) {
/* EXT_draw_buffers :
The maximum number of draw buffers is implementation-dependent. The
number of draw buffers supported can be queried by calling
GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An
INVALID_VALUE error is generated if <buffersLength> is greater than
MAX_DRAW_BUFFERS_EXT.
*/
return mContext->ErrorInvalidValue("drawBuffersWEBGL: invalid <buffers> (buffers.length > GL_MAX_DRAW_BUFFERS)");
}
for (uint32_t i = 0; i < buffersLength; i++)
{
/* EXT_draw_buffers :
If the GL is bound to a draw framebuffer object, the <i>th buffer listed
in <bufs> must be COLOR_ATTACHMENT<i>_EXT or NONE. Specifying a
buffer out of order, BACK, or COLOR_ATTACHMENT<m>_EXT where <m> is
greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT,
will generate the error INVALID_OPERATION.
*/
/* WEBGL_draw_buffers :
The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter.
*/
if (buffers[i] != LOCAL_GL_NONE &&
buffers[i] != GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + i)) {
return mContext->ErrorInvalidOperation("drawBuffersWEBGL: invalid operation (buffers[i] must be GL_NONE or GL_COLOR_ATTACHMENTi)");
}
}
mContext->MakeContextCurrent();
mContext->GL()->fDrawBuffers(buffersLength, buffers.Elements());
mContext->DrawBuffers(buffers);
}
bool WebGLExtensionDrawBuffers::IsSupported(const WebGLContext* context)

View File

@ -7,6 +7,7 @@
#define WEBGLVERTEXARRAY_H_
#include "WebGLObjectModel.h"
#include "WebGLBuffer.h"
#include "WebGLVertexAttribData.h"
#include "nsWrapperCache.h"

View File

@ -35,6 +35,8 @@ if CONFIG['MOZ_WEBGL']:
'WebGLContextUtils.cpp',
'WebGLContextReporter.cpp',
'WebGLContextValidate.cpp',
'WebGLContextFramebufferOperations.cpp',
'WebGLContextVertexArray.cpp',
'WebGLElementArrayCache.cpp',
'WebGLExtensionBase.cpp',
'WebGLExtensionCompressedTextureATC.cpp',

View File

@ -8,5 +8,52 @@
interface WebGL2RenderingContext : WebGLRenderingContext {
/* draw buffers */
const GLenum COLOR_ATTACHMENT1 = 0x8CE1;
const GLenum COLOR_ATTACHMENT2 = 0x8CE2;
const GLenum COLOR_ATTACHMENT3 = 0x8CE3;
const GLenum COLOR_ATTACHMENT4 = 0x8CE4;
const GLenum COLOR_ATTACHMENT5 = 0x8CE5;
const GLenum COLOR_ATTACHMENT6 = 0x8CE6;
const GLenum COLOR_ATTACHMENT7 = 0x8CE7;
const GLenum COLOR_ATTACHMENT8 = 0x8CE8;
const GLenum COLOR_ATTACHMENT9 = 0x8CE9;
const GLenum COLOR_ATTACHMENT10 = 0x8CEA;
const GLenum COLOR_ATTACHMENT11 = 0x8CEB;
const GLenum COLOR_ATTACHMENT12 = 0x8CEC;
const GLenum COLOR_ATTACHMENT13 = 0x8CED;
const GLenum COLOR_ATTACHMENT14 = 0x8CEE;
const GLenum COLOR_ATTACHMENT15 = 0x8CEF;
const GLenum DRAW_BUFFER0 = 0x8825;
const GLenum DRAW_BUFFER1 = 0x8826;
const GLenum DRAW_BUFFER2 = 0x8827;
const GLenum DRAW_BUFFER3 = 0x8828;
const GLenum DRAW_BUFFER4 = 0x8829;
const GLenum DRAW_BUFFER5 = 0x882A;
const GLenum DRAW_BUFFER6 = 0x882B;
const GLenum DRAW_BUFFER7 = 0x882C;
const GLenum DRAW_BUFFER8 = 0x882D;
const GLenum DRAW_BUFFER9 = 0x882E;
const GLenum DRAW_BUFFER10 = 0x882F;
const GLenum DRAW_BUFFER11 = 0x8830;
const GLenum DRAW_BUFFER12 = 0x8831;
const GLenum DRAW_BUFFER13 = 0x8832;
const GLenum DRAW_BUFFER14 = 0x8833;
const GLenum DRAW_BUFFER15 = 0x8834;
const GLenum MAX_COLOR_ATTACHMENTS = 0x8CDF;
const GLenum MAX_DRAW_BUFFERS = 0x8824;
/* vertex array objects */
const GLenum VERTEX_ARRAY_BINDING = 0x85B5;
void bindVertexArray(WebGLVertexArray? arrayObject);
WebGLVertexArray? createVertexArray();
void drawBuffers(sequence<GLenum> buffers);
void deleteVertexArray(WebGLVertexArray? arrayObject);
[WebGLHandlesContextLoss] GLboolean isVertexArray(WebGLVertexArray? arrayObject);
};