Bug 1083936 - WebGL2: Add texImage3D - r=jgilbert,smaug
authorBenoit Jacob <bjacob@mozilla.com>
Thu, 16 Oct 2014 22:03:34 -0400
changeset 224210 35da3c99e658095b737623ab8e543fb740f872a4
parent 224200 667e3bebacc711b772c846f2f1d96601cb1be642
child 224213 cbf06fe7f47a049662b813109522b64198da7362
push idunknown
push userunknown
push dateunknown
reviewersjgilbert, smaug
bugs1083936
milestone36.0a1
Bug 1083936 - WebGL2: Add texImage3D - r=jgilbert,smaug
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextTextures.cpp
dom/canvas/WebGLContextUtils.cpp
dom/webidl/WebGL2RenderingContext.webidl
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextSymbols.h
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -61,17 +61,21 @@ public:
 
 
     // -------------------------------------------------------------------------
     // Texture objects - WebGL2ContextTextures.cpp
 
     void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
     void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
                       GLsizei depth);
-
+    void TexImage3D(GLenum target, GLint level, GLenum internalformat,
+                    GLsizei width, GLsizei height, GLsizei depth,
+                    GLint border, GLenum format, GLenum type,
+                    const Nullable<dom::ArrayBufferView> &pixels,
+                    ErrorResult& rv);
     void TexSubImage3D(GLenum target, 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);
     void TexSubImage3D(GLenum target, GLint level,
                        GLint xoffset, GLint yoffset, GLint zoffset,
                        GLenum format, GLenum type, dom::ImageData* data,
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -200,16 +200,129 @@ WebGL2Context::TexStorage3D(GLenum targe
                           WebGLImageDataStatus::UninitializedImageData);
         w = std::max(1, w >> 1);
         h = std::max(1, h >> 1);
         d = std::max(1, d >> 1);
     }
 }
 
 void
+WebGL2Context::TexImage3D(GLenum target, GLint level, GLenum internalformat,
+                          GLsizei width, GLsizei height, GLsizei depth,
+                          GLint border, GLenum format, GLenum type,
+                          const Nullable<dom::ArrayBufferView> &pixels,
+                          ErrorResult& rv)
+{
+    if (IsContextLost())
+        return;
+
+    void* data;
+    size_t dataLength;
+    js::Scalar::Type jsArrayType;
+    if (pixels.IsNull()) {
+        data = nullptr;
+        dataLength = 0;
+        jsArrayType = js::Scalar::TypeMax;
+    } else {
+        const ArrayBufferView& view = pixels.Value();
+        view.ComputeLengthAndData();
+
+        data = view.Data();
+        dataLength = view.Length();
+        jsArrayType = JS_GetArrayBufferViewType(view.Obj());
+    }
+
+    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))
+    {
+        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);
+}
+
+void
 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)
 {
     if (IsContextLost())
         return;
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -862,16 +862,17 @@ InfoFrom(WebGLTexImageFunc func, WebGLTe
         case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
         case WebGLTexImageFunc::CompTexImage:    return "compressedTexImage2D";
         case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
         default:
             MOZ_CRASH();
         }
     case WebGLTexDimensions::Tex3D:
         switch (func) {
+        case WebGLTexImageFunc::TexImage:        return "texImage3D";
         case WebGLTexImageFunc::TexSubImage:     return "texSubImage3D";
         case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage3D";
         case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage3D";
         default:
             MOZ_CRASH();
         }
     default:
         MOZ_CRASH();
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -337,16 +337,21 @@ interface WebGL2RenderingContext : WebGL
 
     /* Renderbuffer objects */
     void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
 
     /* Texture objects */
     void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
     void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
                       GLsizei depth);
+    [Throws]
+    void texImage3D(GLenum target, GLint level, GLenum internalformat,
+                    GLsizei width, GLsizei height, GLsizei depth,
+                    GLint border, GLenum format,
+                    GLenum type, ArrayBufferView? pixels);
     [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
                                 ArrayBufferView? pixels);
     [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                 GLenum format, GLenum type, ImageData? data);
     [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                 GLenum format, GLenum type, HTMLImageElement image);
     [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -1248,17 +1248,17 @@ GLContext::InitWithPrefix(const char *pr
 
                 MarkUnsupported(GLFeature::map_buffer_range);
                 ClearSymbols(mapBufferRangeSymbols);
             }
         }
 
         if (IsSupported(GLFeature::texture_3D)) {
             SymLoadStruct coreSymbols[] = {
-                // TexImage3D is not required for WebGL2 so not queried here.
+                { (PRFuncPtr*) &mSymbols.fTexImage3D, { "TexImage3D", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3D", nullptr } },
                 END_SYMBOLS
             };
 
             SymLoadStruct extSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fTexSubImage3D, { "TexSubImage3DEXT", "TexSubImage3DOES", nullptr } },
                 END_SYMBOLS
             };
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -3127,16 +3127,31 @@ public:
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fTexStorage3D);
         mSymbols.fTexStorage3D(target, levels, internalformat, width, height, depth);
         AFTER_GL_CALL;
     }
 
 // -----------------------------------------------------------------------------
 // 3D Textures
+    void fTexImage3D(GLenum target, GLint level,
+                     GLint internalFormat,
+                     GLsizei width, GLsizei height, GLsizei depth,
+                     GLint border, GLenum format, GLenum type,
+                     const GLvoid * data)
+    {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fTexImage3D);
+        mSymbols.fTexImage3D(target, level, internalFormat,
+                             width, height, depth,
+                             border, format, type,
+                             data);
+        AFTER_GL_CALL;
+    }
+
     void fTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
                         GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                         GLenum format, GLenum type, const GLvoid* pixels)
     {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fTexSubImage3D);
         mSymbols.fTexSubImage3D(target, level, xoffset, yoffset, zoffset,
                                 width, height, depth, format, type,
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -637,16 +637,22 @@ struct GLContextSymbols
     typedef void (GLAPIENTRY * PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint* value);
     PFNGLUNIFORM3UIVPROC fUniform3uiv;
     typedef void (GLAPIENTRY * PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint* value);
     PFNGLUNIFORM4UIVPROC fUniform4uiv;
     typedef GLint (GLAPIENTRY * PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar* name);
     PFNGLGETFRAGDATALOCATIONPROC fGetFragDataLocation;
 
     // 3D Textures
+    typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level,
+                                                     GLenum internalFormat,
+                                                     GLenum width, GLsizei height, GLsizei depth,
+                                                     GLint border, GLenum format, GLenum type,
+                                                     const GLvoid* pixels);
+    PFNGLTEXIMAGE3DPROC fTexImage3D;
     typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset,
                                                         GLint yoffset, GLint zoffset, GLsizei width,
                                                         GLsizei height, GLsizei depth, GLenum format,
                                                         GLenum type, const GLvoid* pixels);
     PFNGLTEXSUBIMAGE3DPROC fTexSubImage3D;
     typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset,
                                                             GLint yoffset, GLint zoffset, GLint x,
                                                             GLint y, GLsizei width, GLsizei height);