--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -243,14 +243,13 @@ public:
private:
WebGL2Context();
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info);
-
};
} // namespace mozilla
#endif
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -1,14 +1,15 @@
/* -*- 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 "WebGL2Context.h"
+#include "WebGLContextUtils.h"
#include "GLContext.h"
using namespace mozilla;
using namespace mozilla::dom;
bool
WebGL2Context::ValidateSizedInternalFormat(GLenum internalformat, const char* info)
{
@@ -189,23 +190,111 @@ WebGL2Context::TexStorage3D(GLenum targe
h = std::max(1, h >> 1);
d = std::max(1, d >> 1);
}
gl->fTexStorage3D(target, levels, internalformat, width, height, depth);
}
void
-WebGL2Context::TexSubImage3D(GLenum target, GLint level,
+WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const Nullable<dom::ArrayBufferView>& pixels,
ErrorResult& rv)
{
- MOZ_CRASH("Not Implemented.");
+ if (IsContextLost())
+ return;
+
+ if (pixels.IsNull())
+ return ErrorInvalidValue("texSubImage3D: pixels must not be null!");
+
+ const 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))
+ {
+ return;
+ }
+
+ if (type != existingType) {
+ return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
+ }
+
+ js::Scalar::Type jsArrayType = JS_GetArrayBufferViewType(view.Obj());
+ 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())
+ tex->DoDeferredImageInitialization(texImageTarget, level);
+
+ 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);
+
}
void
WebGL2Context::TexSubImage3D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLenum format, GLenum type, dom::ImageData* data,
ErrorResult& rv)
{