Compare commits

...

2 Commits

Author SHA1 Message Date
roytam1 f1d1e16669 import changes from `dev' branch of rmottola/Arctic-Fox: 1 month ago
roytam1 00b0a024a4 import changes from `dev' branch of rmottola/Arctic-Fox: 1 month ago
  1. 2
      b2g/app/b2g.js
  2. 22
      dom/canvas/CanvasRenderingContext2D.cpp
  3. 9
      dom/canvas/CanvasRenderingContext2D.h
  4. 13
      dom/canvas/WebGL2Context.cpp
  5. 24
      dom/canvas/WebGL2Context.h
  6. 2
      dom/canvas/WebGL2ContextDraw.cpp
  7. 95
      dom/canvas/WebGL2ContextFramebuffers.cpp
  8. 66
      dom/canvas/WebGL2ContextRenderbuffers.cpp
  9. 485
      dom/canvas/WebGL2ContextTextures.cpp
  10. 212
      dom/canvas/WebGLContext.cpp
  11. 281
      dom/canvas/WebGLContext.h
  12. 13
      dom/canvas/WebGLContextFramebufferOperations.cpp
  13. 1173
      dom/canvas/WebGLContextGL.cpp
  14. 469
      dom/canvas/WebGLContextTextures.cpp
  15. 4
      dom/canvas/WebGLContextUtils.cpp
  16. 3
      dom/canvas/WebGLContextUtils.h
  17. 34
      dom/canvas/WebGLContextValidate.cpp
  18. 80
      dom/canvas/WebGLFramebuffer.cpp
  19. 11
      dom/canvas/WebGLFramebuffer.h
  20. 285
      dom/canvas/WebGLTexture.cpp
  21. 206
      dom/canvas/WebGLTexture.h
  22. 1419
      dom/canvas/WebGLTextureUpload.cpp
  23. 3
      dom/canvas/moz.build
  24. 7
      dom/canvas/nsICanvasRenderingContextInternal.h
  25. 15
      dom/html/HTMLCanvasElement.cpp
  26. 7
      dom/html/HTMLCanvasElement.h
  27. 40
      dom/media/CanvasCaptureMediaStream.cpp
  28. 5
      dom/media/CanvasCaptureMediaStream.h
  29. 5
      dom/webidl/WebGL2RenderingContext.webidl
  30. 6
      embedding/test/browser.ini
  31. 87
      embedding/test/browser_bug1204626.js
  32. 3
      embedding/test/bug1204626_doc0.html
  33. 5
      embedding/test/bug1204626_doc1.html
  34. 1
      embedding/test/moz.build
  35. 39
      gfx/gl/GLScreenBuffer.cpp
  36. 2
      gfx/gl/GLScreenBuffer.h
  37. 3
      gfx/gl/GLTextureImage.h
  38. 4
      gfx/gl/SharedSurface.h
  39. 5
      gfx/thebes/gfxPrefs.h
  40. 10
      image/ClippedImage.cpp
  41. 4
      image/ClippedImage.h
  42. 24
      image/DecodePool.cpp
  43. 41
      image/Decoder.cpp
  44. 80
      image/Decoder.h
  45. 40
      image/DecoderFactory.cpp
  46. 41
      image/DecoderFactory.h
  47. 42
      image/DecoderFlags.h
  48. 45
      image/Deinterlacer.cpp
  49. 50
      image/Deinterlacer.h
  50. 37
      image/Downscaler.cpp
  51. 16
      image/Downscaler.h
  52. 14
      image/DynamicImage.cpp
  53. 6
      image/FrameAnimator.cpp
  54. 8
      image/FrozenImage.cpp
  55. 4
      image/FrozenImage.h
  56. 11
      image/Image.h
  57. 46
      image/ImageFactory.cpp
  58. 4
      image/ImageOps.cpp
  59. 8
      image/ImageWrapper.cpp
  60. 10
      image/OrientedImage.cpp
  61. 4
      image/OrientedImage.h
  62. 486
      image/RasterImage.cpp
  63. 70
      image/RasterImage.h
  64. 80
      image/SurfaceCache.cpp
  65. 111
      image/SurfaceCache.h
  66. 56
      image/SurfaceFlags.h
  67. 46
      image/VectorImage.cpp
  68. 133
      image/decoders/nsBMPDecoder.cpp
  69. 6
      image/decoders/nsBMPDecoder.h
  70. 165
      image/decoders/nsGIFDecoder2.cpp
  71. 6
      image/decoders/nsGIFDecoder2.h
  72. 833
      image/decoders/nsICODecoder.cpp
  73. 106
      image/decoders/nsICODecoder.h
  74. 101
      image/decoders/nsIconDecoder.cpp
  75. 6
      image/decoders/nsIconDecoder.h
  76. 16
      image/decoders/nsJPEGDecoder.cpp
  77. 5
      image/decoders/nsJPEGDecoder.h
  78. 80
      image/decoders/nsPNGDecoder.cpp
  79. 3
      image/decoders/nsPNGDecoder.h
  80. 90
      image/imgFrame.cpp
  81. 4
      image/imgFrame.h
  82. 17
      image/imgIContainer.idl
  83. 5
      image/imgLoader.cpp
  84. 36
      image/imgTools.cpp
  85. 2
      image/moz.build
  86. 12
      image/test/crashtests/crashtests.list
  87. BIN
      image/test/crashtests/invalid-disposal-method-1.gif
  88. BIN
      image/test/crashtests/invalid-disposal-method-2.gif
  89. BIN
      image/test/crashtests/invalid-disposal-method-3.gif
  90. 0
      image/test/crashtests/invalid_ico_height.ico
  91. 0
      image/test/crashtests/invalid_ico_width.ico
  92. 3
      image/test/gtest/TestDecoders.cpp
  93. 6
      image/test/gtest/TestMetadata.cpp
  94. 5
      image/test/mochitest/test_has_transparency.html
  95. 31
      image/test/reftest/downscaling/downscale-png.html
  96. BIN
      image/test/reftest/downscaling/png-interlaced.png
  97. BIN
      image/test/reftest/downscaling/png-normal.png
  98. 23
      image/test/reftest/downscaling/reftest.list
  99. BIN
      image/test/reftest/ico/cur/pointer.cur
  100. 5
      image/test/reftest/ico/ico-bmp-corrupted/reftest.list
  101. Some files were not shown because too many files have changed in this diff Show More

2
b2g/app/b2g.js

@ -62,7 +62,6 @@ pref("browser.cache.memory_limit", 2048); // 2 MB
/* image cache prefs */
pref("image.cache.size", 1048576); // bytes
pref("image.high_quality_downscaling.enabled", false);
pref("canvas.image.cache.limit", 20971520); // 20 MB
/* offline cache prefs */
@ -326,6 +325,7 @@ pref("media.gonk.enabled", true);
pref("media.video-queue.default-size", 3);
// optimize images' memory usage
pref("image.downscale-during-decode.enabled", true);
pref("image.decode-only-on-draw.enabled", true);
pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */
// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.

22
dom/canvas/CanvasRenderingContext2D.cpp

@ -949,7 +949,9 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
, mIPC(false)
, mDrawObserver(nullptr)
, mIsEntireFrameInvalid(false)
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
, mPredictManyRedrawCalls(false)
, mIsCapturedFrameInvalid(false)
, mPathTransformWillUpdate(false)
, mInvalidateCount(0)
{
sNumLivingContexts++;
@ -1054,6 +1056,7 @@ CanvasRenderingContext2D::Reset()
// no longer be valid.
mIsEntireFrameInvalid = false;
mPredictManyRedrawCalls = false;
mIsCapturedFrameInvalid = false;
return NS_OK;
}
@ -1112,6 +1115,8 @@ CanvasRenderingContext2D::StyleColorToString(const nscolor& aColor, nsAString& a
nsresult
CanvasRenderingContext2D::Redraw()
{
mIsCapturedFrameInvalid = true;
if (mIsEntireFrameInvalid) {
return NS_OK;
}
@ -1133,6 +1138,8 @@ CanvasRenderingContext2D::Redraw()
void
CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
{
mIsCapturedFrameInvalid = true;
++mInvalidateCount;
if (mIsEntireFrameInvalid) {
@ -1170,6 +1177,8 @@ CanvasRenderingContext2D::DidRefresh()
void
CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
{
mIsCapturedFrameInvalid = true;
if (mIsEntireFrameInvalid) {
++mInvalidateCount;
return;
@ -5710,6 +5719,17 @@ CanvasRenderingContext2D::MarkContextClean()
mInvalidateCount = 0;
}
void
CanvasRenderingContext2D::MarkContextCleanForFrameCapture()
{
mIsCapturedFrameInvalid = false;
}
bool
CanvasRenderingContext2D::IsContextCleanForFrameCapture()
{
return !mIsCapturedFrameInvalid;
}
bool
CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager *aManager)

9
dom/canvas/CanvasRenderingContext2D.h

@ -527,6 +527,8 @@ public:
LayerManager *aManager) override;
virtual bool ShouldForceInactiveLayer(LayerManager *aManager) override;
void MarkContextClean() override;
void MarkContextCleanForFrameCapture() override;
bool IsContextCleanForFrameCapture() override;
NS_IMETHOD SetIsIPC(bool isIPC) override;
// this rect is in canvas device space
void Redraw(const mozilla::gfx::Rect &r);
@ -819,6 +821,13 @@ protected:
*/
bool mPredictManyRedrawCalls;
/**
* Flag to avoid unnecessary surface copies to FrameCaptureListeners in the
* case when the canvas is not currently being drawn into and not rendered
* but canvas capturing is still ongoing.
*/
bool mIsCapturedFrameInvalid;
// This is stored after GetThebesSurface has been called once to avoid
// excessive ThebesSurface initialization overhead.
nsRefPtr<gfxASurface> mThebesSurface;

13
dom/canvas/WebGL2Context.cpp

@ -77,8 +77,7 @@ static const gl::GLFeature kRequiredFeatures[] = {
gl::GLFeature::element_index_uint,
gl::GLFeature::frag_color_float,
gl::GLFeature::frag_depth,
gl::GLFeature::framebuffer_blit,
gl::GLFeature::framebuffer_multisample,
gl::GLFeature::framebuffer_object,
gl::GLFeature::get_integer_indexed,
gl::GLFeature::get_integer64_indexed,
gl::GLFeature::gpu_shader4,
@ -164,6 +163,16 @@ WebGLContext::InitWebGL2()
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
&mGLMaxUniformBufferBindings);
if (MinCapabilityMode()) {
mGLMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE;
mGLMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS;
} else {
gl->fGetIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE,
(GLint*) &mGLMax3DTextureSize);
gl->fGetIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS,
(GLint*) &mGLMaxArrayTextureLayers);
}
mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);

24
dom/canvas/WebGL2Context.h

@ -8,6 +8,12 @@
#include "WebGLContext.h"
/*
* Minimum value constants define in 6.2 State Tables of OpenGL ES - 3.0.4
*/
#define MINVALUE_GL_MAX_3D_TEXTURE_SIZE 256
#define MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS 256
namespace mozilla {
class ErrorResult;
@ -55,13 +61,20 @@ public:
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval);
void FramebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture* texture, GLint level, GLint layer);
void InvalidateFramebuffer(GLenum target, const dom::Sequence<GLenum>& attachments,
ErrorResult& rv);
void InvalidateSubFramebuffer (GLenum target, const dom::Sequence<GLenum>& attachments, GLint x, GLint y,
GLsizei width, GLsizei height, ErrorResult& rv);
void ReadBuffer(GLenum mode);
// -------------------------------------------------------------------------
// Renderbuffer objects - WebGL2ContextRenderbuffers.cpp
void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat,
GLenum pname, JS::MutableHandleValue retval,
ErrorResult& rv);
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
GLsizei width, GLsizei height);
@ -357,15 +370,10 @@ public:
private:
WebGL2Context();
JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) override;
virtual bool IsTexParamValid(GLenum pname) const override;
void UpdateBoundQuery(GLenum target, WebGLQuery* query);
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info);
// CreateVertexArrayImpl is assumed to be infallible.
virtual WebGLVertexArray* CreateVertexArrayImpl() override;
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override;

2
dom/canvas/WebGL2ContextDraw.cpp

@ -13,7 +13,7 @@ namespace mozilla {
void
WebGL2Context::DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset)
{
MOZ_CRASH("Not Implemented.");
GenerateWarning("drawRangeElements: Not Implemented.");
}
} // namespace mozilla

95
dom/canvas/WebGL2ContextFramebuffers.cpp

@ -330,16 +330,92 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
mask, filter);
}
void
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
static bool
ValidateTextureLayerAttachment(GLenum attachment)
{
MOZ_CRASH("Not Implemented.");
if (LOCAL_GL_COLOR_ATTACHMENT0 < attachment &&
attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
{
return true;
}
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
case LOCAL_GL_STENCIL_ATTACHMENT:
return true;
}
return false;
}
void
WebGL2Context::GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat, GLenum pname, JS::MutableHandleValue retval)
WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
WebGLTexture* texture, GLint level, GLint layer)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
if (!ValidateFramebufferTarget(target, "framebufferTextureLayer"))
return;
if (!ValidateTextureLayerAttachment(attachment))
return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment);
if (texture) {
if (texture->IsDeleted()) {
return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid "
"texture object.");
}
if (level < 0)
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
switch (texture->Target()) {
case LOCAL_GL_TEXTURE_3D:
if ((GLuint) layer >= mGLMax3DTextureSize) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_3D_TEXTURE_SIZE");
}
break;
case LOCAL_GL_TEXTURE_2D_ARRAY:
if ((GLuint) layer >= mGLMaxArrayTextureLayers) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_ARRAY_TEXTURE_LAYERS");
}
break;
default:
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
}
} else {
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
}
WebGLFramebuffer* fb;
switch (target) {
case LOCAL_GL_FRAMEBUFFER:
case LOCAL_GL_DRAW_FRAMEBUFFER:
fb = mBoundDrawFramebuffer;
break;
case LOCAL_GL_READ_FRAMEBUFFER:
fb = mBoundReadFramebuffer;
break;
default:
MOZ_CRASH("Bad target.");
}
if (!fb) {
return ErrorInvalidOperation("framebufferTextureLayer: cannot modify"
" framebuffer 0.");
}
fb->FramebufferTextureLayer(attachment, texture, level, layer);
}
// Map attachments intended for the default buffer, to attachments for a non-
@ -522,13 +598,4 @@ WebGL2Context::ReadBuffer(GLenum mode)
gl->Screen()->SetReadBuffer(mode);
}
void
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
GLenum internalFormat,
GLsizei width, GLsizei height)
{
RenderbufferStorage_base("renderbufferStorageMultisample", target, samples,
internalFormat, width, height);
}
} // namespace mozilla

66
dom/canvas/WebGL2ContextRenderbuffers.cpp

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "WebGL2Context.h"
#include "GLContext.h"
#include "WebGLContextUtils.h"
namespace mozilla {
void
WebGL2Context::GetInternalformatParameter(JSContext* cx, GLenum target,
GLenum internalformat, GLenum pname,
JS::MutableHandleValue retval,
ErrorResult& rv)
{
if (IsContextLost())
return;
if (target != LOCAL_GL_RENDERBUFFER) {
return ErrorInvalidEnumInfo("getInternalfomratParameter: target must be "
"RENDERBUFFER. Was:", target);
}
// GL_INVALID_ENUM is generated if internalformat is not color-,
// depth-, or stencil-renderable.
// TODO: When format table queries lands.
if (pname != LOCAL_GL_SAMPLES) {
return ErrorInvalidEnumInfo("getInternalformatParameter: pname must be SAMPLES. "
"Was:", pname);
}
GLint* samples = nullptr;
GLint sampleCount = 0;
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat,
LOCAL_GL_NUM_SAMPLE_COUNTS, 1, &sampleCount);
if (sampleCount > 0) {
samples = new GLint[sampleCount];
gl->fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalformat, LOCAL_GL_SAMPLES,
sampleCount, samples);
}
JSObject* obj = dom::Int32Array::Create(cx, this, sampleCount, samples);
if (!obj) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
delete[] samples;
retval.setObjectOrNull(obj);
}
void
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
GLenum internalFormat,
GLsizei width, GLsizei height)
{
RenderbufferStorage_base("renderbufferStorageMultisample", target, samples,
internalFormat, width, height);
}
} // namespace mozilla

485
dom/canvas/WebGL2ContextTextures.cpp

@ -10,485 +10,126 @@
namespace mozilla {
bool
WebGL2Context::ValidateSizedInternalFormat(GLenum internalformat, const char* info)
{
switch (internalformat) {
// Sized Internal Formats
// https://www.khronos.org/opengles/sdk/docs/man3/html/glTexStorage2D.xhtml
case LOCAL_GL_R8:
case LOCAL_GL_R8_SNORM:
case LOCAL_GL_R16F:
case LOCAL_GL_R32F:
case LOCAL_GL_R8UI:
case LOCAL_GL_R8I:
case LOCAL_GL_R16UI:
case LOCAL_GL_R16I:
case LOCAL_GL_R32UI:
case LOCAL_GL_R32I:
case LOCAL_GL_RG8:
case LOCAL_GL_RG8_SNORM:
case LOCAL_GL_RG16F:
case LOCAL_GL_RG32F:
case LOCAL_GL_RG8UI:
case LOCAL_GL_RG8I:
case LOCAL_GL_RG16UI:
case LOCAL_GL_RG16I:
case LOCAL_GL_RG32UI:
case LOCAL_GL_RG32I:
case LOCAL_GL_RGB8:
case LOCAL_GL_SRGB8:
case LOCAL_GL_RGB565:
case LOCAL_GL_RGB8_SNORM:
case LOCAL_GL_R11F_G11F_B10F:
case LOCAL_GL_RGB9_E5:
case LOCAL_GL_RGB16F:
case LOCAL_GL_RGB32F:
case LOCAL_GL_RGB8UI:
case LOCAL_GL_RGB8I:
case LOCAL_GL_RGB16UI:
case LOCAL_GL_RGB16I:
case LOCAL_GL_RGB32UI:
case LOCAL_GL_RGB32I:
case LOCAL_GL_RGBA8:
case LOCAL_GL_SRGB8_ALPHA8:
case LOCAL_GL_RGBA8_SNORM:
case LOCAL_GL_RGB5_A1:
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB10_A2:
case LOCAL_GL_RGBA16F:
case LOCAL_GL_RGBA32F:
case LOCAL_GL_RGBA8UI:
case LOCAL_GL_RGBA8I:
case LOCAL_GL_RGB10_A2UI:
case LOCAL_GL_RGBA16UI:
case LOCAL_GL_RGBA16I:
case LOCAL_GL_RGBA32I:
case LOCAL_GL_RGBA32UI:
case LOCAL_GL_DEPTH_COMPONENT16:
case LOCAL_GL_DEPTH_COMPONENT24:
case LOCAL_GL_DEPTH_COMPONENT32F:
case LOCAL_GL_DEPTH24_STENCIL8:
case LOCAL_GL_DEPTH32F_STENCIL8:
return true;
}
if (IsCompressedTextureFormat(internalformat))
return true;
nsCString name;
EnumName(internalformat, &name);
ErrorInvalidEnum("%s: invalid internal format %s", info, name.get());
return false;
}
/** Validates parameters to texStorage{2D,3D} */
bool
WebGL2Context::ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info)
{
// GL_INVALID_OPERATION is generated if the default texture object is curently bound to target.
WebGLTexture* tex = ActiveBoundTextureForTarget(target);
if (!tex) {
ErrorInvalidOperation("%s: no texture is bound to target %s", info, EnumName(target));
return false;
}
// GL_INVALID_OPERATION is generated if the texture object currently bound to target already has
// GL_TEXTURE_IMMUTABLE_FORMAT set to GL_TRUE.
if (tex->IsImmutable()) {
ErrorInvalidOperation("%s: texture bound to target %s is already immutable", info, EnumName(target));
return false;
}
// GL_INVALID_ENUM is generated if internalformat is not a valid sized internal format.
if (!ValidateSizedInternalFormat(internalformat, info))
return false;
// GL_INVALID_VALUE is generated if width, height or levels are less than 1.
if (width < 1) { ErrorInvalidValue("%s: width is < 1", info); return false; }
if (height < 1) { ErrorInvalidValue("%s: height is < 1", info); return false; }
if (depth < 1) { ErrorInvalidValue("%s: depth is < 1", info); return false; }
if (levels < 1) { ErrorInvalidValue("%s: levels is < 1", info); return false; }
// GL_INVALID_OPERATION is generated if levels is greater than floor(log2(max(width, height, depth)))+1.
if (FloorLog2(std::max(std::max(width, height), depth)) + 1 < levels) {
ErrorInvalidOperation("%s: too many levels for given texture dimensions", info);
return false;
}
return true;
}
// -------------------------------------------------------------------------
// Texture objects
void
WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
WebGL2Context::TexStorage2D(GLenum rawTexTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height)
{
if (IsContextLost())
const char funcName[] = "TexStorage2D";
TexTarget texTarget;
WebGLTexture* tex;
if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
return;
// GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
if (target != LOCAL_GL_TEXTURE_2D && target != LOCAL_GL_TEXTURE_CUBE_MAP)
return ErrorInvalidEnum("texStorage2D: target is not TEXTURE_2D or TEXTURE_CUBE_MAP");
if (!ValidateTexStorage(target, levels, internalformat, width, height, 1, "texStorage2D"))
return;
GetAndFlushUnderlyingGLErrors();
gl->fTexStorage2D(target, levels, internalformat, width, height);
GLenum error = GetAndFlushUnderlyingGLErrors();
if (error) {
return GenerateWarning("texStorage2D generated error %s", ErrorName(error));
}
WebGLTexture* tex = ActiveBoundTextureForTarget(target);
tex->SetImmutable();
const size_t facesCount = (target == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
GLsizei w = width;
GLsizei h = height;
for (size_t l = 0; l < size_t(levels); l++) {
for (size_t f = 0; f < facesCount; f++) {
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
l, w, h, 1,
internalformat,
WebGLImageDataStatus::UninitializedImageData);
}
w = std::max(1, w / 2);
h = std::max(1, h / 2);
}
tex->TexStorage2D(texTarget, levels, internalFormat, width, height);
}
void
WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat,
WebGL2Context::TexStorage3D(GLenum rawTexTarget, GLsizei levels, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth)
{
if (IsContextLost())
const char funcName[] = "texStorage3D";
TexTarget texTarget;
WebGLTexture* tex;
if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
return;
// GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
if (target != LOCAL_GL_TEXTURE_3D)
return ErrorInvalidEnum("texStorage3D: target is not TEXTURE_3D");
if (!ValidateTexStorage(target, levels, internalformat, width, height, depth, "texStorage3D"))
return;
GetAndFlushUnderlyingGLErrors();
gl->fTexStorage3D(target, levels, internalformat, width, height, depth);
GLenum error = GetAndFlushUnderlyingGLErrors();
if (error) {
return GenerateWarning("texStorage3D generated error %s", ErrorName(error));
}
WebGLTexture* tex = ActiveBoundTextureForTarget(target);
tex->SetImmutable();
GLsizei w = width;
GLsizei h = height;
GLsizei d = depth;
for (size_t l = 0; l < size_t(levels); l++) {
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, 0),
l, w, h, d,
internalformat,
WebGLImageDataStatus::UninitializedImageData);
w = std::max(1, w >> 1);
h = std::max(1, h >> 1);
d = std::max(1, d >> 1);
}
tex->TexStorage3D(texTarget, levels, internalFormat, width, height, depth);
}
void
WebGL2Context::TexImage3D(GLenum target, GLint level, GLenum internalformat,
WebGL2Context::TexImage3D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLenum format, GLenum type,
const dom::Nullable<dom::ArrayBufferView> &pixels,
ErrorResult& rv)
GLint border, GLenum unpackFormat, GLenum unpackType,
const dom::Nullable<dom::ArrayBufferView>& maybeView,
ErrorResult& out_rv)
{
if (IsContextLost())
return;
void* data;
size_t dataLength;
js::Scalar::Type jsArrayType;
if (pixels.IsNull()) {
data = nullptr;
dataLength = 0;
jsArrayType = js::Scalar::MaxTypedArrayViewType;
} else {
const dom::ArrayBufferView& view = pixels.Value();
view.ComputeLengthAndData();
data = view.Data();
dataLength = view.Length();
jsArrayType = view.Type();
}
const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
if (!ValidateTexImageTarget(target, func, dims))
return;
TexImageTarget texImageTarget = target;
if (!ValidateTexImage(texImageTarget, level, internalformat,
0, 0, 0,
width, height, depth,
border, format, type, func, dims))
const char funcName[] = "texImage3D";
TexImageTarget texImageTarget;
WebGLTexture* tex;
if (!ValidateTexImageTarget(this, rawTexImageTarget, funcName, &texImageTarget, &tex))
{
return;
}
if (!ValidateTexInputData(type, jsArrayType, func, dims))
return;
TexInternalFormat effectiveInternalFormat =
EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
if (effectiveInternalFormat == LOCAL_GL_NONE) {
return ErrorInvalidOperation("texImage3D: bad combination of internalformat and type");
}
// we need to find the exact sized format of the source data. Slightly abusing
// EffectiveInternalFormatFromInternalFormatAndType for that purpose. Really, an unsized source format
// is the same thing as an unsized internalformat.
TexInternalFormat effectiveSourceFormat =
EffectiveInternalFormatFromInternalFormatAndType(format, type);
MOZ_ASSERT(effectiveSourceFormat != LOCAL_GL_NONE); // should have validated format/type combo earlier
const size_t srcbitsPerTexel = GetBitsPerTexel(effectiveSourceFormat);
MOZ_ASSERT((srcbitsPerTexel % 8) == 0); // should not have compressed formats here.
size_t srcTexelSize = srcbitsPerTexel / 8;
CheckedUint32 checked_neededByteLength =
GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
uint32_t bytesNeeded = checked_neededByteLength.value();
if (dataLength && dataLength < bytesNeeded)
return ErrorInvalidOperation("texImage3D: not enough data for operation (need %d, have %d)",
bytesNeeded, dataLength);
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
if (!tex)
return ErrorInvalidOperation("texImage3D: no texture is bound to this target");
if (tex->IsImmutable()) {
return ErrorInvalidOperation(
"texImage3D: disallowed because the texture "
"bound to this target has already been made immutable by texStorage3D");
}
GLenum driverType = LOCAL_GL_NONE;
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
DriverFormatsFromEffectiveInternalFormat(gl,
effectiveInternalFormat,
&driverInternalFormat,
&driverFormat,
&driverType);
MakeContextCurrent();
GetAndFlushUnderlyingGLErrors();
gl->fTexImage3D(texImageTarget.get(), level,
driverInternalFormat,
width, height, depth,
0, driverFormat, driverType,
data);
GLenum error = GetAndFlushUnderlyingGLErrors();
if (error) {
return GenerateWarning("texImage3D generated error %s", ErrorName(error));
}
tex->SetImageInfo(texImageTarget, level,
width, height, depth,
effectiveInternalFormat,
data ? WebGLImageDataStatus::InitializedImageData
: WebGLImageDataStatus::UninitializedImageData);
tex->TexImage3D(texImageTarget, level, internalFormat, width, height, depth, border,
unpackFormat, unpackType, maybeView, &out_rv);
}
void
WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type,
const dom::Nullable<dom::ArrayBufferView>& pixels,
ErrorResult& rv)
GLenum unpackFormat, GLenum unpackType,
const dom::Nullable<dom::ArrayBufferView>& maybeView,
ErrorResult& out_rv)
{
if (IsContextLost())
return;
if (pixels.IsNull())
return ErrorInvalidValue("texSubImage3D: pixels must not be null!");
const dom::ArrayBufferView& view = pixels.Value();
view.ComputeLengthAndData();
const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
if (!ValidateTexImageTarget(rawTarget, func, dims))
return;
TexImageTarget texImageTarget(rawTarget);
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
if (!tex) {
return ErrorInvalidOperation("texSubImage3D: no texture bound on active texture unit");
}
if (!tex->HasImageInfoAt(texImageTarget, level)) {
return ErrorInvalidOperation("texSubImage3D: no previously defined texture image");
}
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
TexType existingType = LOCAL_GL_NONE;
UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
&existingUnsizedInternalFormat,
&existingType);
if (!ValidateTexImage(texImageTarget, level, existingEffectiveInternalFormat.get(),
xoffset, yoffset, zoffset,
width, height, depth,
0, format, type, func, dims))
const char funcName[] = "texSubImage3D";
TexImageTarget texImageTarget;
WebGLTexture* tex;
if (!ValidateTexImageTarget(this, rawTexImageTarget, funcName, &texImageTarget, &tex))
{
return;
}
if (type != existingType) {
return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
}
js::Scalar::Type jsArrayType = view.Type();
void* data = view.Data();
size_t dataLength = view.Length();
if (!ValidateTexInputData(type, jsArrayType, func, dims))
return;
const size_t bitsPerTexel = GetBitsPerTexel(existingEffectiveInternalFormat);
MOZ_ASSERT((bitsPerTexel % 8) == 0); // should not have compressed formats here.
size_t srcTexelSize = bitsPerTexel / 8;
if (width == 0 || height == 0 || depth == 0)
return; // no effect, we better return right now
CheckedUint32 checked_neededByteLength =
GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.isValid())
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
uint32_t bytesNeeded = checked_neededByteLength.value();
if (dataLength < bytesNeeded)
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, dataLength);
if (imageInfo.HasUninitializedImageData()) {
bool coversWholeImage = xoffset == 0 &&
yoffset == 0 &&
zoffset == 0 &&
width == imageInfo.Width() &&
height == imageInfo.Height() &&
depth == imageInfo.Depth();
if (coversWholeImage) {
tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
} else {
if (!tex->EnsureInitializedImageData(texImageTarget, level))
return;
}
}
GLenum driverType = LOCAL_GL_NONE;
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
DriverFormatsFromEffectiveInternalFormat(gl,
existingEffectiveInternalFormat,
&driverInternalFormat,
&driverFormat,
&driverType);
MakeContextCurrent();
gl->fTexSubImage3D(texImageTarget.get(), level,
xoffset, yoffset, zoffset,
width, height, depth,
driverFormat, driverType, data);
tex->TexSubImage3D(texImageTarget, level, xOffset, yOffset, zOffset, width, height,
depth, unpackFormat, unpackType, maybeView, &out_rv);
}
void
WebGL2Context::TexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLenum format, GLenum type, dom::ImageData* data,
ErrorResult& rv)
GLint xOffset, GLint yOffset, GLint zOffset,
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
ErrorResult& out_rv)
{
MOZ_CRASH("Not Implemented.");
GenerateWarning("texSubImage3D: Not implemented.");
}
void
WebGL2Context::CopyTexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLint xOffset, GLint yOffset, GLint zOffset,
GLint x, GLint y, GLsizei width, GLsizei height)
{
MOZ_CRASH("Not Implemented.");
GenerateWarning("copyTexSubImage3D: Not implemented.");
}
void
WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat,
WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLsizei imageSize, const dom::ArrayBufferView& data)
GLint border, GLsizei imageSize, const dom::ArrayBufferView& view)
{
MOZ_CRASH("Not Implemented.");
GenerateWarning("compressedTexImage3D: Not implemented.");
}
void
WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize, const dom::ArrayBufferView& data)
GLenum unpackFormat, GLsizei imageSize, const dom::ArrayBufferView& view)
{
MOZ_CRASH("Not Implemented.");
GenerateWarning("compressedTexSubImage3D: Not implemented.");
}
JS::Value
WebGL2Context::GetTexParameterInternal(const TexTarget& target, GLenum pname)
bool
WebGL2Context::IsTexParamValid(GLenum pname) const
{
switch (pname) {
case LOCAL_GL_TEXTURE_BASE_LEVEL:
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
case LOCAL_GL_TEXTURE_COMPARE_MODE:
case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
case LOCAL_GL_TEXTURE_MAX_LEVEL:
case LOCAL_GL_TEXTURE_SWIZZLE_A:
case LOCAL_GL_TEXTURE_SWIZZLE_B:
case LOCAL_GL_TEXTURE_SWIZZLE_G:
case LOCAL_GL_TEXTURE_SWIZZLE_R:
case LOCAL_GL_TEXTURE_WRAP_R:
{
GLint i = 0;
gl->fGetTexParameteriv(target.get(), pname, &i);
return JS::NumberValue(uint32_t(i));
}
case LOCAL_GL_TEXTURE_BASE_LEVEL:
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
case LOCAL_GL_TEXTURE_COMPARE_MODE:
case LOCAL_GL_TEXTURE_IMMUTABLE_FORMAT:
case LOCAL_GL_TEXTURE_IMMUTABLE_LEVELS:
case LOCAL_GL_TEXTURE_MAX_LEVEL:
case LOCAL_GL_TEXTURE_SWIZZLE_A:
case LOCAL_GL_TEXTURE_SWIZZLE_B:
case LOCAL_GL_TEXTURE_SWIZZLE_G:
case LOCAL_GL_TEXTURE_SWIZZLE_R:
case LOCAL_GL_TEXTURE_WRAP_R:
case LOCAL_GL_TEXTURE_MAX_LOD:
case LOCAL_GL_TEXTURE_MIN_LOD:
return true;
case LOCAL_GL_TEXTURE_MAX_LOD:
case LOCAL_GL_TEXTURE_MIN_LOD:
{
GLfloat f = 0.0f;
gl->fGetTexParameterfv(target.get(), pname, &f);
return JS::NumberValue(float(f));
}
default:
return WebGLContext::IsTexParamValid(pname);
}
return WebGLContext::GetTexParameterInternal(target, pname);
}
} // namespace mozilla

212
dom/canvas/WebGLContext.cpp

@ -220,6 +220,7 @@ WebGLContext::WebGLContext()
{
mGeneration = 0;
mInvalidated = false;
mCapturedFrameInvalidated = false;
mShouldPresent = true;
mResetLayer = true;
mOptionsFrozen = false;
@ -271,6 +272,8 @@ WebGLContext::WebGLContext()
mGLMaxDrawBuffers = 1;
mGLMaxTransformFeedbackSeparateAttribs = 0;
mGLMaxUniformBufferBindings = 0;
mGLMax3DTextureSize = 0;
mGLMaxArrayTextureLayers = 0;
// See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
mPixelStorePackAlignment = 4;
@ -411,10 +414,12 @@ WebGLContext::DestroyResourcesAndContext()
void
WebGLContext::Invalidate()
{
if (mInvalidated)
if (!mCanvasElement)
return;
if (!mCanvasElement)
mCapturedFrameInvalidated = true;
if (mInvalidated)
return;
nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
@ -667,6 +672,7 @@ PopulateCapFallbackQueue(const SurfaceCaps& baseCaps,
static bool
CreateOffscreen(GLContext* gl, const WebGLContextOptions& options,
const nsCOMPtr<nsIGfxInfo>& gfxInfo, WebGLContext* webgl,
layers::LayersBackend layersBackend,
layers::ISurfaceAllocator* surfAllocator)
{
SurfaceCaps baseCaps;
@ -682,10 +688,14 @@ CreateOffscreen(GLContext* gl, const WebGLContextOptions& options,
if (!baseCaps.alpha)
baseCaps.premultAlpha = true;
if (gl->IsANGLE() || gl->GetContextType() == GLContextType::GLX) {
if (gl->IsANGLE() ||
(gl->GetContextType() == GLContextType::GLX &&
layersBackend == LayersBackend::LAYERS_OPENGL))
{
// We can't use no-alpha formats on ANGLE yet because of:
// https://code.google.com/p/angleproject/issues/detail?id=764
// GLX only supports GL_RGBA pixmaps as well.
// GLX only supports GL_RGBA pixmaps as well. Since we can't blit from
// an RGB FB to GLX's RGBA FB, force RGBA when surface sharing.
baseCaps.alpha = true;
}
@ -754,7 +764,8 @@ WebGLContext::CreateOffscreenGL(bool forceEnabled)
if (!gl)
break;
if (!CreateOffscreen(gl, mOptions, gfxInfo, this, surfAllocator))
if (!CreateOffscreen(gl, mOptions, gfxInfo, this,
GetCompositorBackendType(), surfAllocator))
break;
if (!InitAndValidateGL())
@ -1272,6 +1283,17 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
return canvasLayer.forget();
}
layers::LayersBackend
WebGLContext::GetCompositorBackendType() const
{
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
if (docWidget) {
layers::LayerManager* layerManager = docWidget->GetLayerManager();
return layerManager->GetCompositorBackendType();
}
return LayersBackend::LAYERS_NONE;
}
void
WebGLContext::GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval)
{
@ -1350,6 +1372,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfiel
bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
bool drawBuffersIsEnabled = IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
bool shouldOverrideDrawBuffers = false;
bool usingDefaultFrameBuffer = !mBoundDrawFramebuffer;
GLenum currentDrawBuffers[WebGLContext::kMaxColorAttachments];
@ -1367,7 +1390,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfiel
GLenum drawBuffersCommand[WebGLContext::kMaxColorAttachments] = { LOCAL_GL_NONE };
for(int32_t i = 0; i < mGLMaxDrawBuffers; i++) {
for (int32_t i = 0; i < mGLMaxDrawBuffers; i++) {
GLint temp;
gl->fGetIntegerv(LOCAL_GL_DRAW_BUFFER0 + i, &temp);
currentDrawBuffers[i] = temp;
@ -1378,6 +1401,16 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfiel
if (currentDrawBuffers[i] != drawBuffersCommand[i])
shouldOverrideDrawBuffers = true;
}
// When clearing the default framebuffer, we must be clearing only
// GL_BACK, and nothing else, or else gl may return an error. We will
// only use the first element of currentDrawBuffers in this case.
if (usingDefaultFrameBuffer) {
gl->Screen()->SetDrawBuffer(LOCAL_GL_BACK);
if (currentDrawBuffers[0] == LOCAL_GL_COLOR_ATTACHMENT0)
currentDrawBuffers[0] = LOCAL_GL_BACK;
shouldOverrideDrawBuffers = false;
}
// calling draw buffers can cause resolves on adreno drivers so
// we try to avoid calling it
if (shouldOverrideDrawBuffers)
@ -1423,8 +1456,13 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfiel
// Restore GL state after clearing.
if (initializeColorBuffer) {
if (shouldOverrideDrawBuffers) {
gl->fDrawBuffers(mGLMaxDrawBuffers, currentDrawBuffers);
if (drawBuffersIsEnabled) {
if (usingDefaultFrameBuffer) {
gl->Screen()->SetDrawBuffer(currentDrawBuffers[0]);
} else if (shouldOverrideDrawBuffers) {
gl->fDrawBuffers(mGLMaxDrawBuffers, currentDrawBuffers);
}
}
gl->fColorMask(mColorWriteMask[0],
@ -1806,158 +1844,6 @@ WebGLContext::DidRefresh()
}
}
bool
WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
GLint level, GLenum internalFormat,
GLenum format, GLenum type,
mozilla::dom::Element& elt)
{
if (type == LOCAL_GL_HALF_FLOAT_OES &&
!gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float))
{
type = LOCAL_GL_HALF_FLOAT;
}
if (!ValidateTexImageFormatAndType(format, type,
WebGLTexImageFunc::TexImage,
WebGLTexDimensions::Tex2D))
{
return false;
}
HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
if (!video)
return false;
uint16_t readyState;
if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)
{
//No frame inside, just return
return false;
}
// If it doesn't have a principal, just bail
nsCOMPtr<nsIPrincipal> principal = video->GetCurrentPrincipal();
if (!principal)
return false;
mozilla::layers::ImageContainer* container = video->GetImageContainer();
if (!container)
return false;
if (video->GetCORSMode() == CORS_NONE) {
bool subsumes;
nsresult rv = mCanvasElement->NodePrincipal()->Subsumes(principal, &subsumes);
if (NS_FAILED(rv) || !subsumes) {
GenerateWarning("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
"See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
return false;
}
}
AutoLockImage lockedImage(container);
Image* srcImage = lockedImage.GetImage();
if (!srcImage) {
return false;
}
gl->MakeCurrent();
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
const WebGLTexture::ImageInfo& info = tex->ImageInfoAt(texImageTarget, 0);
bool dimensionsMatch = info.Width() == srcImage->GetSize().width &&
info.Height() == srcImage->GetSize().height;
if (!dimensionsMatch) {
// we need to allocation
gl->fTexImage2D(texImageTarget.get(), level, internalFormat,
srcImage->GetSize().width, srcImage->GetSize().height,
0, format, type, nullptr);
}
const gl::OriginPos destOrigin = mPixelStoreFlipY ? gl::OriginPos::BottomLeft
: gl::OriginPos::TopLeft;
bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage,
srcImage->GetSize(),
tex->mGLName,
texImageTarget.get(),
destOrigin);
if (ok) {
TexInternalFormat effectiveInternalFormat =
EffectiveInternalFormatFromInternalFormatAndType(internalFormat,
type);
MOZ_ASSERT(effectiveInternalFormat != LOCAL_GL_NONE);
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width,
srcImage->GetSize().height, 1,
effectiveInternalFormat,
WebGLImageDataStatus::InitializedImageData);
tex->Bind(TexImageTargetToTexTarget(texImageTarget));
}
return ok;
}
void
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xoffset,
GLint yoffset, GLenum format, GLenum type,
dom::Element* elt, ErrorResult* const out_rv)
{
// TODO: Consolidate all the parameter validation
// checks. Instead of spreading out the cheks in multple
// places, consolidate into one spot.
if (IsContextLost())
return;
if (!ValidateTexImageTarget(rawTexImageTarget,
WebGLTexImageFunc::TexSubImage,
WebGLTexDimensions::Tex2D))
{
ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
return;
}
const TexImageTarget texImageTarget(rawTexImageTarget);
if (level < 0)
return ErrorInvalidValue("texSubImage2D: level is negative");
const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
if (level > maxLevel) {
ErrorInvalidValue("texSubImage2D: level %d is too large, max is %d",
level, maxLevel);
return;
}
WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
if (!tex)
return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
const TexInternalFormat internalFormat = imageInfo.EffectiveInternalFormat();
// Trying to handle the video by GPU directly first
if (TexImageFromVideoElement(texImageTarget, level,
internalFormat.get(), format, type, *elt))
{
return;
}
RefPtr<gfx::DataSourceSurface> data;
WebGLTexelFormat srcFormat;
nsLayoutUtils::SurfaceFromElementResult res = SurfaceFromElement(*elt);
*out_rv = SurfaceFromElementResultToImageSurface(res, data, &srcFormat);
if (out_rv->Failed() || !data)
return;
gfx::IntSize size = data->GetSize();
uint32_t byteLength = data->Stride() * size.height;
TexSubImage2D_base(texImageTarget.get(), level, xoffset, yoffset, size.width,
size.height, data->Stride(), format, type, data->GetData(),
byteLength, js::Scalar::MaxTypedArrayViewType, srcFormat,
res.mIsPremultiplied);
}
size_t
RoundUpToMultipleOf(size_t value, size_t multiple)
{
@ -1965,6 +1851,12 @@ RoundUpToMultipleOf(size_t value, size_t multiple)
return overshoot - (overshoot % multiple);
}