Bug 1130616 - Support EXT_color_buffer_half_float on ANGLE. - r=jrmuizel,khuey
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 24 Feb 2015 14:09:09 -0800
changeset 248881 110d66c1fd6e2018ffb298f320d345bdc48a068a
parent 248880 65e87c0b6aef31eb56634a546a0150e81a2f4def
child 248882 331e34783b63352f861c3e58bf4309b9093da4a6
push id7860
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:46:02 +0000
treeherdermozilla-aurora@8ac636cd51f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, khuey
bugs1130616
milestone39.0a1
Bug 1130616 - Support EXT_color_buffer_half_float on ANGLE. - r=jrmuizel,khuey
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextFramebufferOperations.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextState.cpp
dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLTexelConversions.h
dom/canvas/test/webgl-mochitest.ini
dom/canvas/test/webgl-mochitest/test_webgl_color_buffer_float.html
dom/webidl/WebGLRenderingContext.webidl
gfx/angle/src/libGLESv2/libGLESv2.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextSymbols.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1847,16 +1847,22 @@ WebGLContext::TexImageFromVideoElement(c
         tex->Bind(TexImageTargetToTexTarget(texImageTarget));
     }
 
     srcImage = nullptr;
     container->UnlockCurrentImage();
     return ok;
 }
 
+size_t mozilla::RoundUpToMultipleOf(size_t value, size_t multiple)
+{
+    size_t overshoot = value + multiple - 1;
+    return overshoot - (overshoot % multiple);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
     : mWebGL(webgl)
     , mNeedsChange(NeedsChange(webgl))
 {
     if (mNeedsChange) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
@@ -1870,16 +1876,17 @@ WebGLContext::ScopedMaskWorkaround::~Sco
 {
     if (mNeedsChange) {
         mWebGL.gl->fColorMask(mWebGL.mColorWriteMask[0],
                               mWebGL.mColorWriteMask[1],
                               mWebGL.mColorWriteMask[2],
                               mWebGL.mColorWriteMask[3]);
     }
 }
+
 ////////////////////////////////////////////////////////////////////////////////
 // XPCOM goop
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
   mCanvasElement,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1087,19 +1087,17 @@ protected:
     static CheckedUint32 GetImageSize(GLsizei height, GLsizei width,
                                       GLsizei depth, uint32_t pixelSize,
                                       uint32_t alignment);
 
     virtual JS::Value GetTexParameterInternal(const TexTarget& target,
                                               GLenum pname);
 
     // Returns x rounded to the next highest multiple of y.
-    static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x,
-                                                 CheckedUint32 y)
-    {
+    static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
         return ((x + y - 1) / y) * y;
     }
 
     inline void InvalidateBufferFetching()
     {
         mBufferFetchingIsVerified = false;
         mBufferFetchingHasPerVertex = false;
         mMaxFetchedVertices = 0;
@@ -1688,11 +1686,13 @@ public:
     void UnregisterMemoryPressureEvent();
 
 private:
     ~WebGLObserver();
 
     WebGLContext* mWebGL;
 };
 
+size_t RoundUpToMultipleOf(size_t value, size_t multiple);
+
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -44,41 +44,51 @@ WebGLContext::Clear(GLbitfield mask)
         ScopedMaskWorkaround autoMask(*this);
         gl->fClear(mask);
     }
 
     Invalidate();
     mShouldPresent = true;
 }
 
-static GLclampf
-GLClampFloat(GLclampf val)
+static GLfloat
+GLClampFloat(GLfloat val)
 {
     if (val < 0.0)
         return 0.0;
 
     if (val > 1.0)
         return 1.0;
 
     return val;
 }
 
 void
-WebGLContext::ClearColor(GLclampf r, GLclampf g,
-                             GLclampf b, GLclampf a)
+WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
 {
     if (IsContextLost())
         return;
 
     MakeContextCurrent();
-    mColorClearValue[0] = GLClampFloat(r);
-    mColorClearValue[1] = GLClampFloat(g);
-    mColorClearValue[2] = GLClampFloat(b);
-    mColorClearValue[3] = GLClampFloat(a);
+
+    const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
+                                            IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float));
+    if (!supportsFloatColorBuffers) {
+        r = GLClampFloat(r);
+        g = GLClampFloat(g);
+        b = GLClampFloat(b);
+        a = GLClampFloat(a);
+    }
+
     gl->fClearColor(r, g, b, a);
+
+    mColorClearValue[0] = r;
+    mColorClearValue[1] = g;
+    mColorClearValue[2] = b;
+    mColorClearValue[3] = a;
 }
 
 void
 WebGLContext::ClearDepth(GLclampf v)
 {
     if (IsContextLost())
         return;
 
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1858,16 +1858,94 @@ SetFullAlpha(void* data, GLenum format, 
 
         return true;
     }
 
     MOZ_ASSERT(false, "Unhandled case, how'd we get here?");
     return false;
 }
 
+static void
+ReadPixelsAndConvert(gl::GLContext* gl, GLint x, GLint y, GLsizei width, GLsizei height,
+                     GLenum readFormat, GLenum readType, size_t pixelStorePackAlignment,
+                     GLenum destFormat, GLenum destType, void* destBytes)
+{
+    if (readFormat == destFormat && readType == destType) {
+        gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes);
+        return;
+    }
+
+    if (readFormat == LOCAL_GL_RGBA &&
+        readType == LOCAL_GL_HALF_FLOAT &&
+        destFormat == LOCAL_GL_RGBA &&
+        destType == LOCAL_GL_FLOAT)
+    {
+        size_t readBytesPerPixel = sizeof(uint16_t) * 4;
+        size_t destBytesPerPixel = sizeof(float) * 4;
+
+        size_t readBytesPerRow = readBytesPerPixel * width;
+
+        size_t readStride = RoundUpToMultipleOf(readBytesPerRow, pixelStorePackAlignment);
+        size_t destStride = RoundUpToMultipleOf(destBytesPerPixel * width,
+                                                pixelStorePackAlignment);
+
+        size_t bytesNeeded = ((height - 1) * readStride) + readBytesPerRow;
+        UniquePtr<uint8_t[]> readBuffer(new uint8_t[bytesNeeded]);
+
+        gl->fReadPixels(x, y, width, height, readFormat, readType, readBuffer.get());
+
+        size_t channelsPerRow = width * 4;
+        for (size_t j = 0; j < (size_t)height; j++) {
+            uint16_t* src = (uint16_t*)(readBuffer.get()) + j*readStride;
+            float* dst = (float*)(destBytes) + j*destStride;
+
+            uint16_t* srcEnd = src + channelsPerRow;
+            while (src != srcEnd) {
+                *dst = unpackFromFloat16(*src);
+
+                ++src;
+                ++dst;
+            }
+        }
+
+        return;
+    }
+
+    MOZ_CRASH("bad format/type");
+}
+
+static bool
+IsFormatAndTypeUnpackable(GLenum format, GLenum type)
+{
+    switch (type) {
+    case LOCAL_GL_UNSIGNED_BYTE:
+    case LOCAL_GL_FLOAT:
+    case LOCAL_GL_HALF_FLOAT:
+    case LOCAL_GL_HALF_FLOAT_OES:
+        switch (format) {
+        case LOCAL_GL_ALPHA:
+        case LOCAL_GL_RGB:
+        case LOCAL_GL_RGBA:
+            return true;
+        default:
+            return false;
+        }
+
+    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+        return format == LOCAL_GL_RGBA;
+
+    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+        return format == LOCAL_GL_RGB;
+
+    default:
+        return false;
+    }
+}
+
 void
 WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
                          GLsizei height, GLenum format,
                          GLenum type, const Nullable<ArrayBufferView> &pixels,
                          ErrorResult& rv)
 {
     if (IsContextLost())
         return;
@@ -1878,69 +1956,71 @@ WebGLContext::ReadPixels(GLint x, GLint 
     }
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("readPixels: negative size passed");
 
     if (pixels.IsNull())
         return ErrorInvalidValue("readPixels: null destination buffer");
 
+    if (!IsFormatAndTypeUnpackable(format, type))
+        return ErrorInvalidEnum("readPixels: Bad format or type.");
+
     const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
-    uint32_t channels = 0;
+    int channels = 0;
 
     // Check the format param
     switch (format) {
-        case LOCAL_GL_ALPHA:
-            channels = 1;
-            break;
-        case LOCAL_GL_RGB:
-            channels = 3;
-            break;
-        case LOCAL_GL_RGBA:
-            channels = 4;
-            break;
-        default:
-            return ErrorInvalidEnum("readPixels: Bad format");
+    case LOCAL_GL_ALPHA:
+        channels = 1;
+        break;
+    case LOCAL_GL_RGB:
+        channels = 3;
+        break;
+    case LOCAL_GL_RGBA:
+        channels = 4;
+        break;
+    default:
+        MOZ_CRASH("bad `format`");
     }
 
-    uint32_t bytesPerPixel = 0;
-    int requiredDataType = 0;
 
     // Check the type param
-    bool isReadTypeValid = false;
-    bool isReadTypeFloat = false;
+    int bytesPerPixel;
+    int requiredDataType;
     switch (type) {
-        case LOCAL_GL_UNSIGNED_BYTE:
-            isReadTypeValid = true;
-            bytesPerPixel = 1*channels;
-            requiredDataType = js::Scalar::Uint8;
-            break;
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-            isReadTypeValid = true;
-            bytesPerPixel = 2;
-            requiredDataType = js::Scalar::Uint16;
-            break;
-        case LOCAL_GL_FLOAT:
-            if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) ||
-                IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
-            {
-                isReadTypeValid = true;
-                isReadTypeFloat = true;
-                bytesPerPixel = 4*channels;
-                requiredDataType = js::Scalar::Float32;
-            }
-            break;
+    case LOCAL_GL_UNSIGNED_BYTE:
+        bytesPerPixel = 1*channels;
+        requiredDataType = js::Scalar::Uint8;
+        break;
+
+    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+        bytesPerPixel = 2;
+        requiredDataType = js::Scalar::Uint16;
+        break;
+
+    case LOCAL_GL_FLOAT:
+        bytesPerPixel = 4*channels;
+        requiredDataType = js::Scalar::Float32;
+        break;
+
+    case LOCAL_GL_HALF_FLOAT:
+    case LOCAL_GL_HALF_FLOAT_OES:
+        bytesPerPixel = 2*channels;
+        requiredDataType = js::Scalar::Uint16;
+        break;
+
+    default:
+        MOZ_CRASH("bad `type`");
     }
-    if (!isReadTypeValid)
-        return ErrorInvalidEnum("readPixels: Bad type", type);
 
     const ArrayBufferView& pixbuf = pixels.Value();
     int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
 
     // Check the pixels param type
     if (dataType != requiredDataType)
         return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
 
@@ -1983,64 +2063,62 @@ WebGLContext::ReadPixels(GLint x, GLint 
         isSourceTypeFloat = (type == LOCAL_GL_FLOAT ||
                              type == LOCAL_GL_HALF_FLOAT);
     } else {
         ClearBackbufferIfNeeded();
 
         isSourceTypeFloat = false;
     }
 
-    if (isReadTypeFloat != isSourceTypeFloat)
-        return ErrorInvalidOperation("readPixels: Invalid type floatness");
-
     // Check the format and type params to assure they are an acceptable pair (as per spec)
 
-    bool isFormatAndTypeValid = false;
+    const GLenum mainReadFormat = LOCAL_GL_RGBA;
+    const GLenum mainReadType = isSourceTypeFloat ? LOCAL_GL_FLOAT
+                                                  : LOCAL_GL_UNSIGNED_BYTE;
+
+    GLenum auxReadFormat = mainReadFormat;
+    GLenum auxReadType = mainReadType;
 
     // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
     // combination for glReadPixels().
     if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
-        GLenum implType = 0;
-        GLenum implFormat = 0;
-
+        gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
+                         reinterpret_cast<GLint*>(&auxReadFormat));
         gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
-                         reinterpret_cast<GLint*>(&implType));
-        gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
-                         reinterpret_cast<GLint*>(&implFormat));
-
-        if (type == implType && format == implFormat) {
-            isFormatAndTypeValid = true;
-        }
+                         reinterpret_cast<GLint*>(&auxReadType));
     }
 
-    switch (format) {
-        case LOCAL_GL_RGBA: {
-            switch (type) {
-                case LOCAL_GL_UNSIGNED_BYTE:
-                case LOCAL_GL_FLOAT:
-                    isFormatAndTypeValid = true;
-                    break;
-            }
-            break;
+    const bool mainMatches = (format == mainReadFormat && type == mainReadType);
+    const bool auxMatches = (format == auxReadFormat && type == auxReadType);
+    const bool isValid = mainMatches || auxMatches;
+    if (!isValid)
+        return ErrorInvalidOperation("readPixels: Invalid format/type pair");
+
+    GLenum readType = type;
+    if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
+        if (type == LOCAL_GL_FLOAT &&
+            auxReadFormat == format &&
+            auxReadType == LOCAL_GL_HALF_FLOAT)
+        {
+            readType = auxReadType;
         }
     }
 
-    if (!isFormatAndTypeValid) {
-        return ErrorInvalidOperation("readPixels: Invalid format/type pair");
-    }
-
     // Now that the errors are out of the way, on to actually reading
 
     // If we won't be reading any pixels anyways, just skip the actual reading
     if (width == 0 || height == 0)
         return DummyFramebufferOperation("readPixels");
 
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
         // the easy case: we're not reading out-of-range pixels
-        gl->fReadPixels(x, y, width, height, format, type, data);
+
+        // Effectively: gl->fReadPixels(x, y, width, height, format, type, dest);
+        ReadPixelsAndConvert(gl, x, y, width, height, format, readType,
+                             mPixelStorePackAlignment, format, type, data);
     } else {
         // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
         // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
         // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
         // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
         // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
         // to accomodate the potentially different strides (widths).
 
@@ -2079,18 +2157,21 @@ WebGLContext::ReadPixels(GLint x, GLint 
             RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
         uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
 
         // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
         UniquePtr<GLubyte> subrect_data(new (fallible) GLubyte[subrect_byteLength]);
         if (!subrect_data)
             return ErrorOutOfMemory("readPixels: subrect_data");
 
-        gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height,
-                        format, type, subrect_data.get());
+        // Effectively: gl->fReadPixels(subrect_x, subrect_y, subrect_width,
+        //                              subrect_height, format, type, subrect_data.get());
+        ReadPixelsAndConvert(gl, subrect_x, subrect_y, subrect_width, subrect_height,
+                             format, readType, mPixelStorePackAlignment, format, type,
+                             subrect_data.get());
 
         // notice that this for loop terminates because we already checked that subrect_height is at most height
         for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
             GLint subrect_x_in_dest_buffer = subrect_x - x;
             GLint subrect_y_in_dest_buffer = subrect_y - y;
             memcpy(static_cast<GLubyte*>(data)
                      + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
                      + bytesPerPixel * subrect_x_in_dest_buffer, // destination
@@ -3592,17 +3673,17 @@ mozilla::GetWebGLTexelFormat(TexInternal
         case LOCAL_GL_RGB5_A1:                return WebGLTexelFormat::RGBA5551;
         case LOCAL_GL_RGB565:                 return WebGLTexelFormat::RGB565;
         default:
             return WebGLTexelFormat::FormatNotSupportingAnyConversion;
     }
 }
 
 void
-WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
+WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
     if (IsContextLost())
         return;
     MakeContextCurrent();
     gl->fBlendColor(r, g, b, a);
 }
 
 void
 WebGLContext::Flush() {
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -261,25 +261,45 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_BLEND_EQUATION_RGB:
         case LOCAL_GL_BLEND_EQUATION_ALPHA:
         case LOCAL_GL_GENERATE_MIPMAP_HINT: {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             return JS::NumberValue(uint32_t(i));
         }
         case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
+            if (mBoundReadFramebuffer) {
+                FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
+                if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+                    ErrorInvalidOperation("getParameter: Read framebuffer must be"
+                                          " complete before querying"
+                                          " IMPLEMENTATION_COLOR_READ_TYPE.");
+                    return JS::NullValue();
+                }
+            }
+
             GLint i = 0;
             if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                 gl->fGetIntegerv(pname, &i);
             } else {
                 i = LOCAL_GL_UNSIGNED_BYTE;
             }
             return JS::NumberValue(uint32_t(i));
         }
         case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
+            if (mBoundReadFramebuffer) {
+                FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
+                if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+                    ErrorInvalidOperation("getParameter: Read framebuffer must be"
+                                          " complete before querying"
+                                          " IMPLEMENTATION_COLOR_READ_FORMAT.");
+                    return JS::NullValue();
+                }
+            }
+
             GLint i = 0;
             if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                 gl->fGetIntegerv(pname, &i);
             } else {
                 i = LOCAL_GL_RGBA;
             }
             return JS::NumberValue(uint32_t(i));
         }
--- a/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
+++ b/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
@@ -21,14 +21,15 @@ WebGLExtensionColorBufferHalfFloat::~Web
 }
 
 bool
 WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl)
 {
     gl::GLContext* gl = webgl->GL();
 
     // ANGLE doesn't support ReadPixels from a RGBA16F with RGBA/FLOAT.
-    return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float);
+    return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) ||
+           gl->IsANGLE();
 }
 
 IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -124,16 +124,17 @@ WebGLFramebuffer::Attachment::EffectiveI
 
 bool
 WebGLFramebuffer::Attachment::IsReadableFloat() const
 {
     TexInternalFormat internalformat = EffectiveInternalFormat();
     MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
     TexType type = TypeFromInternalFormat(internalformat);
     return type == LOCAL_GL_FLOAT ||
+           type == LOCAL_GL_HALF_FLOAT_OES ||
            type == LOCAL_GL_HALF_FLOAT;
 }
 
 void
 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex,
                                           TexImageTarget target, GLint level)
 {
     mTexturePtr = tex;
@@ -798,16 +799,17 @@ WebGLFramebuffer::CheckFramebufferStatus
         return mStatus;
 
     // Looks good on our end. Let's ask the driver.
     mContext->MakeContextCurrent();
 
     // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
     FinalizeAttachments();
 
+    // TODO: This should not be unconditionally GL_FRAMEBUFFER.
     mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
     return mStatus;
 }
 
 bool
 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
 {
     if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
--- a/dom/canvas/WebGLTexelConversions.h
+++ b/dom/canvas/WebGLTexelConversions.h
@@ -100,17 +100,17 @@ unpackFromFloat16(uint16_t v)
         uint32_t f32Bits;
     };
 
     // grab sign bit
     f32Bits = uint32_t(v & 0x8000) << 16;
     uint16_t exp = (v >> 10) & 0x001F;
     uint16_t mantissa = v & 0x03FF;
 
-    if (exp) {
+    if (!exp) {
         // Handle denormalized numbers
         // Adapted from: OpenGL ES 2.0 Programming Guide Appx.
         // Converting Float to Half-Float
         if (mantissa) {
             exp = 112; // See packToFloat16
             mantissa <<= 1;
             // For every leading zero, decrement the exponent
             // and shift the mantissa to the left
--- a/dom/canvas/test/webgl-mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest.ini
@@ -17,16 +17,18 @@ skip-if = (os == 'b2g') || buildapp == '
 [webgl-mochitest/test_highp_fs.html]
 [webgl-mochitest/test_no_arr_points.html]
 skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942
 [webgl-mochitest/test_noprog_draw.html]
 [webgl-mochitest/test_privileged_exts.html]
 [webgl-mochitest/test_texsubimage_float.html]
 [webgl-mochitest/test_webgl_available.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
+#[webgl-mochitest/test_webgl_color_buffer_float.html]
+# We haven't cleaned up the Try results yet, but let's get this on the books first.
 [webgl-mochitest/test_webgl_conformance.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_request_context.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl_request_mismatch.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
 [webgl-mochitest/test_webgl2_not_exposed.html]
 skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/test_webgl_color_buffer_float.html
@@ -0,0 +1,486 @@
+<html>
+  <head>
+    <meta charset='UTF-8'>
+    <script src='/tests/SimpleTest/SimpleTest.js'></script>
+    <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+  </head>
+  <body>
+<script id='vs' type='x-shader/x-vertex'>
+
+attribute vec2 aVertCoord;
+
+void main(void) {
+  gl_Position = vec4(aVertCoord, 0.0, 1.0);
+}
+
+</script>
+<script id='fs' type='x-shader/x-fragment'>
+
+precision mediump float; // 💩
+
+uniform vec4 uFragColor;
+
+void main(void) {
+  gl_FragColor = uFragColor;
+}
+
+</script>
+
+<canvas id='c' width='200' height='200'></canvas>
+
+<script>
+
+function GetGLSLByElemId(elemId) {
+  var elem = document.getElementById(elemId);
+  if (!elem)
+    throw 'Bad `elemId`: ' + elemId;
+
+  return elem.innerHTML.trim();
+}
+
+function ProgramByElemIds(gl, vsId, fsId) {
+  var vs = gl.createShader(gl.VERTEX_SHADER);
+  gl.shaderSource(vs, GetGLSLByElemId(vsId));
+  gl.compileShader(vs);
+
+  var fs = gl.createShader(gl.FRAGMENT_SHADER);
+  gl.shaderSource(fs, GetGLSLByElemId(fsId));
+  gl.compileShader(fs);
+
+  var prog = gl.createProgram();
+  gl.attachShader(prog, vs);
+  gl.attachShader(prog, fs);
+
+  gl.linkProgram(prog);
+
+  var success = gl.getProgramParameter(prog, gl.LINK_STATUS);
+  if (success)
+      return prog;
+
+  console.log('Error linking program for \'' + vsId + '\' and \'' + fsId + '\'.');
+  console.log('\nLink log: ' + gl.getProgramInfoLog(prog));
+  console.log('\nVert shader log: ' + gl.getShaderInfoLog(vs));
+  console.log('\nFrag shader log: ' + gl.getShaderInfoLog(fs));
+  return null;
+}
+
+var RGBA = 0x1908;
+var UNSIGNED_BYTE = 0x1401;
+var FLOAT = 0x1406;
+var HALF_FLOAT_OES = 0x8D61;
+var HALF_FLOAT = 0x140B;
+var RGBA4 = 0x8056;
+var RGBA8 = 0x8058;
+var RGBA32F = 0x8814;
+var RGBA16F = 0x881A;
+
+function EnumName(val) {
+  switch (val) {
+    case RGBA:
+      return 'RGBA';
+    case UNSIGNED_BYTE:
+      return 'UNSIGNED_BYTE';
+    case FLOAT:
+      return 'FLOAT';
+    case HALF_FLOAT_OES:
+      return 'HALF_FLOAT_OES';
+    case HALF_FLOAT:
+      return 'HALF_FLOAT';
+    case RGBA4:
+      return 'RGBA4';
+    case RGBA32F:
+      return 'RGBA32F';
+    default:
+      throw 'Unknown enum: 0x' + val.toString(16);
+  }
+}
+
+var gl;
+
+function RGBAToString(arr) {
+  return '[' + arr[0].toPrecision(4) + ', ' +
+               arr[1].toPrecision(4) + ', ' +
+               arr[2].toPrecision(4) + ', ' +
+               arr[3].toPrecision(4) + ']';
+}
+
+function TestScreenColor(gl, isFBFloat, r, g, b, a) {
+  var readType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
+
+  var arr;
+  switch (readType) {
+    case gl.UNSIGNED_BYTE:
+      arr = new Uint8Array(4);
+      break;
+
+    case gl.FLOAT:
+      arr = new Float32Array(4);
+      break;
+
+    default:
+      throw 'Bad `readType`.';
+  }
+
+  gl.readPixels(0, 0, 1, 1, gl.RGBA, readType, arr);
+
+  var err = gl.getError();
+  ok(err == 0, 'Should be no errors.');
+  if (err)
+    return;
+
+  var floatArr;
+  switch (readType) {
+    case gl.UNSIGNED_BYTE:
+      floatArr = new Float32Array(4);
+      floatArr[0] = arr[0] / 255.0;
+      floatArr[1] = arr[1] / 255.0;
+      floatArr[2] = arr[2] / 255.0;
+      floatArr[3] = arr[3] / 255.0;
+      break;
+
+    case gl.FLOAT:
+      floatArr = arr;
+      break;
+
+    default:
+      throw 'Bad `readType`.';
+  }
+
+  var testText = RGBAToString(floatArr);
+  var refText = RGBAToString([r, g, b, a]);
+
+  var eps = 1.0 / 255.0;
+  var isSame = (Math.abs(floatArr[0] - r) < eps &&
+                Math.abs(floatArr[1] - g) < eps &&
+                Math.abs(floatArr[2] - b) < eps &&
+                Math.abs(floatArr[3] - a) < eps);
+
+  ok(isSame, 'Should be ' + refText + ', was ' + testText + ',');
+}
+
+function TestReadFormat(gl, isFBFloat, format, type) {
+  var err = gl.getError();
+  if (err) {
+    ok(false, 'Should be no error at start of TestReadFormat(). (0x' + err.toString(16) + ')');
+    return;
+  }
+  var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
+  var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
+
+  var err = gl.getError();
+  if (err) {
+    ok(false, 'Should be no error at start2 of TestReadFormat(). (0x' + err.toString(16) + ')');
+    return;
+  }
+
+  var defaultReadType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
+
+  var formatOk = (format == gl.RGBA &&
+                  type == defaultReadType);
+
+  if (format == implFormat &&
+      type == implType)
+  {
+    formatOk = true;
+  }
+
+  var w = 1;
+  var h = 1;
+  var channels = 4;
+  var arrSize = w * h * channels;
+
+  var arr;
+  switch (type) {
+    case UNSIGNED_BYTE:
+      arr = new Uint8Array(arrSize);
+      break;
+
+    case FLOAT:
+      arr = new Float32Array(arrSize);
+      break;
+
+    case HALF_FLOAT_OES:
+    case HALF_FLOAT:
+      arr = new Uint16Array(arrSize);
+      break;
+
+    default:
+      throw 'Bad `type`: 0x' + type.toString(16);
+  }
+
+  gl.readPixels(0, 0, 1, 1, format, type, arr);
+  var wasOk = gl.getError() == 0;
+
+  var text = 'Should ' + (formatOk ? '' : 'not ') + 'allow reading with ' +
+             EnumName(format) + '/' + EnumName(type) + '.'
+  ok(wasOk == formatOk, text);
+}
+
+function TestError(gl, expectedErr, descText) {
+  var err = gl.getError();
+
+  while (gl.getError()) {}
+
+  ok(err == expectedErr,
+     descText + ': Error should be 0x' + expectedErr.toString(16) + ', was 0x' +
+     err.toString(16) + '.');
+
+  return err;
+}
+
+function AttachRBToCurFB(gl, sizedFormat) {
+  var isSupported;
+  switch (sizedFormat) {
+  case RGBA4:
+    isSupported = true;
+    break;
+
+  case RGBA16F:
+    isSupported = !!gl.getExtension('EXT_color_buffer_half_float');
+    break;
+
+  case RGBA32F:
+    isSupported = !!gl.getExtension('WEBGL_color_buffer_float');
+    break;
+
+  default:
+    throw 'Bad `sizedFormat`.';
+  }
+
+  var rb = gl.createRenderbuffer();
+  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
+  gl.renderbufferStorage(gl.RENDERBUFFER, sizedFormat, 1, 1);
+
+  var correctError = isSupported ? 0 : gl.INVALID_ENUM;
+  var err = TestError(gl, correctError, 'RB specification with supported format');
+  if (err)
+    return false;
+
+  gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
+
+  var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+  var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
+  ok(isComplete, 'Framebuffer should be complete after RB attachment.');
+  return isComplete;
+}
+
+function AttachTexToCurFB(gl, sizedFormat) {
+  var canCreate;
+  var isAttachGuaranteed;
+  var format;
+  var type;
+
+  switch (sizedFormat) {
+  case RGBA8:
+    canCreate = true;
+    isAttachGuaranteed = true;
+    format = RGBA;
+    type = UNSIGNED_BYTE;
+    break;
+
+  case RGBA16F:
+    canCreate = !!gl.getExtension('OES_texture_half_float');
+    isAttachGuaranteed = !!gl.getExtension('EXT_color_buffer_half_float');
+    format = RGBA;
+    type = HALF_FLOAT_OES;
+    break;
+
+  case RGBA32F:
+    canCreate = !!gl.getExtension('OES_texture_float');
+    isAttachGuaranteed = !!gl.getExtension('WEBGL_color_buffer_float');
+    format = RGBA;
+    type = FLOAT;
+    break;
+
+  default:
+    throw 'Bad `sizedFormat`.';
+  }
+
+  var tex = gl.createTexture();
+  gl.bindTexture(gl.TEXTURE_2D, tex);
+  gl.texImage2D(gl.TEXTURE_2D, 0, format, 1, 1, 0, format, type, null);
+
+  var correctError = canCreate ? 0 : gl.INVALID_ENUM;
+  var err = TestError(gl, correctError, 'Tex specification with supported format');
+  if (err)
+    return false;
+
+  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
+
+  var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
+  var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
+
+  if (!isAttachGuaranteed && !isComplete)
+    todo(false, 'Framebuffer needn\'t be complete after tex attachment.');
+  else
+    ok(isComplete, 'Framebuffer should be complete after tex attachment.');
+
+  return isComplete;
+}
+
+function IsFormatFloat(sizedFormat) {
+  switch (sizedFormat) {
+  case RGBA4:
+  case RGBA8:
+    return false;
+
+  case RGBA16F:
+  case RGBA32F:
+    return true;
+
+  default:
+    throw 'Bad `sizedFormat`.';
+  }
+}
+
+function TestType(gl, prog, isTex, sizedFormat) {
+  TestError(gl, 0, 'At start of TestRB()');
+
+  var isAttached = isTex ? AttachTexToCurFB(gl, sizedFormat)
+                         : AttachRBToCurFB(gl, sizedFormat);
+  if (!isAttached)
+    return;
+
+  var isFormatFloat = IsFormatFloat(sizedFormat);
+
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.UNSIGNED_BYTE);
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.FLOAT);
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT);
+  TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT_OES);
+
+  //////////////////////////////////////
+
+  ok(true, 'Drawing:');
+
+  gl.clearColor(0.0, 1.5, 0.5, 1.0);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  if (isFormatFloat)
+    TestScreenColor(gl, isFormatFloat, 0, 1.5, 0.5, 1);
+  else
+    TestScreenColor(gl, isFormatFloat, 0, 1, 0.5, 1);
+
+  ////////
+
+  ok(true, 'Clearing:');
+
+  gl.uniform4f(prog.uFragColor, 0, 0.5, 1.5, 1);
+  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+  if (isFormatFloat)
+    TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.5, 1);
+  else
+    TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.0, 1);
+
+  ////////
+
+  ok(true, 'Blending:');
+
+  gl.enable(gl.BLEND);
+  gl.blendFunc(gl.CONSTANT_COLOR, gl.ZERO);
+  gl.blendColor(0, 10, 0.1, 1);
+
+  gl.uniform4f(prog.uFragColor, 0, 0.5, 15.0, 1);
+  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+
+  if (isFormatFloat)
+    TestScreenColor(gl, isFormatFloat, 0, 5.0, 1.5, 1);
+  else
+    TestScreenColor(gl, isFormatFloat, 0, 0.5, 0.1, 1);
+
+  gl.disable(gl.BLEND);
+
+  //////////////////////////////////////
+}
+
+// Give ourselves a scope to return early from:
+(function() {
+  var canvas = document.getElementById('c');
+  var attribs = {
+    antialias: false,
+    depth: false,
+  };
+  gl = canvas.getContext('experimental-webgl', attribs);
+  if (!gl) {
+    todo(false, 'WebGL is unavailable.');
+    return;
+  }
+
+  var cbf = gl.getExtension('WEBGL_color_buffer_float');
+  var cbhf = gl.getExtension('EXT_color_buffer_half_float');
+
+  //////////////////////////////////////
+
+  gl.viewport(0, 0, 1, 1);
+
+  var prog = ProgramByElemIds(gl, 'vs', 'fs');
+  ok(prog, 'Program should link.');
+  if (!prog)
+    return;
+
+  prog.aVertCoord = gl.getAttribLocation(prog, 'aVertCoord');
+  prog.uFragColor = gl.getUniformLocation(prog, 'uFragColor');
+
+  gl.useProgram(prog);
+
+  var arr = new Float32Array([
+    -1, -1,
+     1, -1,
+    -1,  1,
+     1,  1,
+  ]);
+  var vb = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, vb);
+  gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
+
+  gl.enableVertexAttribArray(0);
+  gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
+
+  //////////////////////////////////////
+
+  var fb = gl.createFramebuffer();
+  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+
+  error = gl.getError();
+  ok(error == 0, 'Should be no errors after setup. (0x' + error.toString(16) + ')');
+
+  //////////////////////////////////////
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA8 texture');
+  TestType(gl, prog, true, RGBA8);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA16F texture');
+  TestType(gl, prog, true, RGBA16F);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA32F texture');
+  TestType(gl, prog, true, RGBA32F);
+
+  ////////
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA4 renderbuffer');
+  TestType(gl, prog, false, RGBA4);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA16F renderbuffer');
+  TestType(gl, prog, false, RGBA16F);
+
+  ok(true, '---------------------------------------------------------------------------');
+  ok(true, 'RGBA32F renderbuffer');
+  TestType(gl, prog, false, RGBA32F);
+
+  ok(true, '---------------------------------------------------------------------------');
+  //////////////////////////////////////
+
+  error = gl.getError();
+  ok(error == 0, 'Should be no errors after test.');
+
+  ok(true, 'TEST COMPLETE');
+})();
+
+</script>
+
+  </body>
+</html>
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -515,32 +515,32 @@ interface WebGLRenderingContext {
 
     void activeTexture(GLenum texture);
     void attachShader(WebGLProgram? program, WebGLShader? shader);
     void bindAttribLocation(WebGLProgram? program, GLuint index, DOMString name);
     void bindBuffer(GLenum target, WebGLBuffer? buffer);
     void bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer);
     void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer);
     void bindTexture(GLenum target, WebGLTexture? texture);
-    void blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
     void blendEquation(GLenum mode);
     void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
     void blendFunc(GLenum sfactor, GLenum dfactor);
     void blendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
                            GLenum srcAlpha, GLenum dstAlpha);
 
     void bufferData(GLenum target, GLsizeiptr size, GLenum usage);
     void bufferData(GLenum target, ArrayBufferView data, GLenum usage);
     void bufferData(GLenum target, ArrayBuffer? data, GLenum usage);
     void bufferSubData(GLenum target, GLintptr offset, ArrayBufferView data);
     void bufferSubData(GLenum target, GLintptr offset, ArrayBuffer? data);
 
     [WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
     void clear(GLbitfield mask);
-    void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
     void clearDepth(GLclampf depth);
     void clearStencil(GLint s);
     void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
     void compileShader(WebGLShader? shader);
 
     void compressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
                               GLsizei width, GLsizei height, GLint border,
                               ArrayBufferView data);
--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp
+++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp
@@ -290,17 +290,17 @@ void GL_APIENTRY glBlendColor(GLclampf r
 {
     EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
           red, green, blue, alpha);
 
     gl::Context* context = gl::getNonLostContext();
 
     if (context)
     {
-        context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
+        context->getState().setBlendColor(red, green, blue, alpha);
     }
 }
 
 void GL_APIENTRY glBlendEquation(GLenum mode)
 {
     glBlendEquationSeparate(mode, mode);
 }
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -881,17 +881,17 @@ public:
     }
 
     void fBindTexture(GLenum target, GLuint texture) {
         BEFORE_GL_CALL;
         mSymbols.fBindTexture(target, texture);
         AFTER_GL_CALL;
     }
 
-    void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
         BEFORE_GL_CALL;
         mSymbols.fBlendColor(red, green, blue, alpha);
         AFTER_GL_CALL;
     }
 
     void fBlendEquation(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fBlendEquation(mode);
@@ -981,17 +981,17 @@ public:
     }
 
     void fClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) {
         BEFORE_GL_CALL;
         mSymbols.fClearBufferuiv(buffer, drawbuffer, value);
         AFTER_GL_CALL;
     }
 
-    void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
+    void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
         BEFORE_GL_CALL;
         mSymbols.fClearColor(r, g, b, a);
         AFTER_GL_CALL;
     }
 
     void fClearStencil(GLint s) {
         BEFORE_GL_CALL;
         mSymbols.fClearStencil(s);
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -44,17 +44,17 @@ struct GLContextSymbols
     typedef void (GLAPIENTRY * PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name);
     PFNGLBINDATTRIBLOCATIONPROC fBindAttribLocation;
     typedef void (GLAPIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
     PFNGLBINDBUFFERPROC fBindBuffer;
     typedef void (GLAPIENTRY * PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
     PFNGLBINDTEXTUREPROC fBindTexture;
     typedef void (GLAPIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array);
     PFNGLBINDVERTEXARRAYPROC fBindVertexArray;
-    typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
     PFNGLBLENDCOLORPROC fBlendColor;
     typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode);
     PFNGLBLENDEQUATIONPROC fBlendEquation;
     typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum, GLenum);
     PFNGLBLENDEQUATIONSEPARATEPROC fBlendEquationSeparate;
     typedef void (GLAPIENTRY * PFNGLBLENDFUNCPROC) (GLenum, GLenum);
     PFNGLBLENDFUNCPROC fBlendFunc;
     typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
@@ -68,17 +68,17 @@ struct GLContextSymbols
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
     PFNGLCLEARBUFFERFIPROC fClearBufferfi;
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat* value);
     PFNGLCLEARBUFFERFVPROC fClearBufferfv;
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint* value);
     PFNGLCLEARBUFFERIVPROC fClearBufferiv;
     typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint* value);
     PFNGLCLEARBUFFERUIVPROC fClearBufferuiv;
-    typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf);
+    typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLfloat, GLfloat, GLfloat, GLfloat);
     PFNGLCLEARCOLORPROC fClearColor;
     typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint);
     PFNGLCLEARSTENCILPROC fClearStencil;
     typedef void (GLAPIENTRY * PFNGLCOLORMASKPROC) (realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha);
     PFNGLCOLORMASKPROC fColorMask;
     typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2D) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *pixels);
     PFNGLCOMPRESSEDTEXIMAGE2D fCompressedTexImage2D;
     typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *pixels);