Bug 1081125 - WebGL2 3D textures - Part 4: implement texSubImage3D - r=jgilbert
authorBenoit Jacob <bjacob@mozilla.com>
Mon, 13 Oct 2014 19:42:29 -0400
changeset 223560 212571e28648a736581a3ee54877bd037fbfb95c
parent 223559 160578cdf1919f0bfd570f6d910d3fddfce24612
child 223561 3be7879798a27ff6625c5161543064f3cb859b74
push idunknown
push userunknown
push dateunknown
reviewersjgilbert
bugs1081125
milestone35.0a1
Bug 1081125 - WebGL2 3D textures - Part 4: implement texSubImage3D - r=jgilbert
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextTextures.cpp
--- 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)
 {