Bug 1265676 - Add copyDecayFormats. - r=ethlin,jrmuizel draft
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 06 Jun 2016 13:41:12 -0700
changeset 375869 f3d791003ff3369f66ed3428b1489871470fb552
parent 375868 3dbe4db5d946f7f0f75aed7686f3117a43ee5544
child 375870 28029a3e13cfeb12ac84207a67855759d511b0ce
push id20405
push userbmo:jgilbert@mozilla.com
push dateMon, 06 Jun 2016 20:45:46 +0000
reviewersethlin, jrmuizel
bugs1265676
milestone49.0a1
Bug 1265676 - Add copyDecayFormats. - r=ethlin,jrmuizel MozReview-Commit-ID: 9axiDOeYxuy
dom/canvas/WebGLFormats.cpp
dom/canvas/WebGLFormats.h
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -34,38 +34,38 @@ FindOrNull(const std::map<K,V*>& dest, c
         return nullptr;
 
     return itr->second;
 }
 
 // Returns a pointer to the in-place value for `key`.
 template<typename K, typename V, typename K2>
 static inline V*
-FindPtrOrNull(const std::map<K,V>& dest, const K2& key)
+FindPtrOrNull(std::map<K,V>& dest, const K2& key)
 {
     auto itr = dest.find(key);
     if (itr == dest.end())
         return nullptr;
 
     return &(itr->second);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 std::map<EffectiveFormat, const CompressedFormatInfo> gCompressedFormatInfoMap;
-std::map<EffectiveFormat, const FormatInfo> gFormatInfoMap;
+std::map<EffectiveFormat, FormatInfo> gFormatInfoMap;
 
 static inline const CompressedFormatInfo*
 GetCompressedFormatInfo(EffectiveFormat format)
 {
     MOZ_ASSERT(!gCompressedFormatInfoMap.empty());
     return FindPtrOrNull(gCompressedFormatInfoMap, format);
 }
 
-static inline const FormatInfo*
+static inline FormatInfo*
 GetFormatInfo_NoLock(EffectiveFormat format)
 {
     MOZ_ASSERT(!gFormatInfoMap.empty());
     return FindPtrOrNull(gFormatInfoMap, format);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -303,16 +303,95 @@ InitFormatInfo()
     AddFormatInfo(FOO(Alpha32F            ), 4,  0,0,0,32, 0,0, UnsizedFormat::A , false, ComponentType::Float);
 
     // OES_texture_half_float
     AddFormatInfo(FOO(Luminance16FAlpha16F), 4, 16,0,0,16, 0,0, UnsizedFormat::LA, false, ComponentType::Float);
     AddFormatInfo(FOO(Luminance16F        ), 2, 16,0,0, 0, 0,0, UnsizedFormat::L , false, ComponentType::Float);
     AddFormatInfo(FOO(Alpha16F            ), 2,  0,0,0,16, 0,0, UnsizedFormat::A , false, ComponentType::Float);
 
 #undef FOO
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    const auto fnSetCopyDecay = [](EffectiveFormat src, EffectiveFormat asR,
+                                   EffectiveFormat asRG, EffectiveFormat asRGB,
+                                   EffectiveFormat asRGBA, EffectiveFormat asL,
+                                   EffectiveFormat asA, EffectiveFormat asLA)
+    {
+        auto& map = GetFormatInfo_NoLock(src)->copyDecayFormats;
+
+        const auto fnSet = [&map](UnsizedFormat uf, EffectiveFormat ef) {
+            if (ef == EffectiveFormat::MAX)
+                return;
+
+            const auto* format = GetFormatInfo_NoLock(ef);
+            MOZ_ASSERT(format->unsizedFormat == uf);
+            AlwaysInsert(map, uf, format);
+        };
+
+        fnSet(UnsizedFormat::R   , asR);
+        fnSet(UnsizedFormat::RG  , asRG);
+        fnSet(UnsizedFormat::RGB , asRGB);
+        fnSet(UnsizedFormat::RGBA, asRGBA);
+        fnSet(UnsizedFormat::L   , asL);
+        fnSet(UnsizedFormat::A   , asA);
+        fnSet(UnsizedFormat::LA  , asLA);
+    };
+
+#define SET_COPY_DECAY(src,asR,asRG,asRGB,asRGBA,asL,asA,asLA) \
+    fnSetCopyDecay(EffectiveFormat::src, EffectiveFormat::asR, EffectiveFormat::asRG,     \
+                   EffectiveFormat::asRGB, EffectiveFormat::asRGBA, EffectiveFormat::asL, \
+                   EffectiveFormat::asA, EffectiveFormat::asLA);
+
+    //////
+
+#define SET_BY_SUFFIX(X) \
+        SET_COPY_DECAY(   R##X, R##X,   MAX,    MAX,     MAX, Luminance##X,      MAX,                    MAX) \
+        SET_COPY_DECAY(  RG##X, R##X, RG##X,    MAX,     MAX, Luminance##X,      MAX,                    MAX) \
+        SET_COPY_DECAY(RGBA##X, R##X, RG##X, RGB##X, RGBA##X, Luminance##X, Alpha##X, Luminance##X##Alpha##X)
+
+    SET_BY_SUFFIX(8)
+    SET_BY_SUFFIX(16F)
+    SET_BY_SUFFIX(32F)
+
+#undef SET_BY_SUFFIX
+
+    //////
+
+#define SET_BY_SUFFIX(X) \
+        SET_COPY_DECAY(   R##X, R##X,   MAX,    MAX,     MAX, MAX, MAX, MAX) \
+        SET_COPY_DECAY(  RG##X, R##X, RG##X,    MAX,     MAX, MAX, MAX, MAX) \
+        SET_COPY_DECAY(RGBA##X, R##X, RG##X, RGB##X, RGBA##X, MAX, MAX, MAX)
+
+    SET_BY_SUFFIX(8I)
+    SET_BY_SUFFIX(8UI)
+
+    SET_BY_SUFFIX(16I)
+    SET_BY_SUFFIX(16UI)
+
+    SET_BY_SUFFIX(32I)
+    SET_BY_SUFFIX(32UI)
+
+#undef SET_BY_SUFFIX
+
+    //////
+
+    SET_COPY_DECAY(      RGB8, R8, RG8,   RGB8,      MAX, Luminance8,    MAX,              MAX)
+    SET_COPY_DECAY(    RGB565, R8, RG8, RGB565,      MAX, Luminance8,    MAX,              MAX)
+    SET_COPY_DECAY(     RGBA4, R8, RG8, RGB565,    RGBA4, Luminance8, Alpha8, Luminance8Alpha8)
+    SET_COPY_DECAY(   RGB5_A1, R8, RG8, RGB565,  RGB5_A1, Luminance8, Alpha8, Luminance8Alpha8)
+    SET_COPY_DECAY(  RGB10_A2, R8, RG8,   RGB8, RGB10_A2, Luminance8, Alpha8,              MAX)
+
+    SET_COPY_DECAY(RGB10_A2UI, R8UI, RG8UI, RGB8UI, RGB10_A2UI, MAX, MAX, MAX)
+
+    SET_COPY_DECAY(SRGB8_ALPHA8, MAX, MAX, MAX, SRGB8_ALPHA8, MAX, Alpha8, MAX)
+
+    SET_COPY_DECAY(R11F_G11F_B10F, R16F, RG16F, R11F_G11F_B10F, MAX, Luminance16F, MAX, MAX)
+
+#undef SET_COPY_DECAY
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 bool gAreFormatTablesInitialized = false;
 
 static void
 EnsureInitFormatTables(const StaticMutexAutoLock&) // Prove that you locked it!
@@ -337,16 +416,22 @@ GetFormat(EffectiveFormat format)
     StaticMutexAutoLock lock(gFormatMapMutex);
     EnsureInitFormatTables(lock);
 
     return GetFormatInfo_NoLock(format);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+const FormatInfo*
+FormatInfo::GetCopyDecayFormat(UnsizedFormat uf) const
+{
+    return FindOrNull(this->copyDecayFormats, uf);
+}
+
 uint8_t
 BytesPerPixel(const PackingInfo& packing)
 {
     uint8_t bytesPerChannel;
     switch (packing.type) {
     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:
@@ -539,33 +624,52 @@ AddUnsizedFormats(FormatUsageAuthority* 
     AddSimpleUnsized(fua, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1, EffectiveFormat::RGB5_A1);
     AddSimpleUnsized(fua, LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_BYTE         , EffectiveFormat::RGB8   );
     AddSimpleUnsized(fua, LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5  , EffectiveFormat::RGB565 );
 
     // L, A, LA
     return AddLegacyFormats_LA8(fua, gl);
 }
 
+void
+FormatUsageInfo::SetRenderable()
+{
+    this->isRenderable = true;
+
+#ifdef DEBUG
+    const auto format = this->format;
+    if (format->isColorFormat) {
+        const auto& map = format->copyDecayFormats;
+        const auto itr = map.find(format->unsizedFormat);
+        MOZ_ASSERT(itr != map.end());
+        MOZ_ASSERT(itr->second == format);
+    }
+#endif
+}
+
 UniquePtr<FormatUsageAuthority>
 FormatUsageAuthority::CreateForWebGL1(gl::GLContext* gl)
 {
     UniquePtr<FormatUsageAuthority> ret(new FormatUsageAuthority);
     const auto ptr = ret.get();
 
     ////////////////////////////////////////////////////////////////////////////
     // Usages
 
     const auto fnSet = [ptr](EffectiveFormat effFormat, bool isRenderable,
                              bool isFilterable)
     {
         MOZ_ASSERT(!ptr->GetUsage(effFormat));
 
         auto usage = ptr->EditUsage(effFormat);
-        usage->isRenderable = isRenderable;
         usage->isFilterable = isFilterable;
+
+        if (isRenderable) {
+            usage->SetRenderable();
+        }
     };
 
     // GLES 2.0.25, p117, Table 4.5
     // RGBA8 is made renderable in WebGL 1.0, "Framebuffer Object Attachments"
     //                              render filter
     //                              able   able
     fnSet(EffectiveFormat::RGBA8  , true, true);
     fnSet(EffectiveFormat::RGBA4  , true, true);
@@ -725,19 +829,22 @@ FormatUsageAuthority::CreateForWebGL2(gl
 
     // For renderable, see GLES 3.0.4, p212 "Framebuffer Completeness"
     // For filterable, see GLES 3.0.4, p161 "...a texture is complete unless..."
 
     const auto fnAllowES3TexFormat = [ptr](GLenum sizedFormat, EffectiveFormat effFormat,
                                            bool isRenderable, bool isFilterable)
     {
         auto usage = ptr->EditUsage(effFormat);
-        usage->isRenderable = isRenderable;
         usage->isFilterable = isFilterable;
 
+        if (isRenderable) {
+            usage->SetRenderable();
+        }
+
         ptr->AllowSizedTexFormat(sizedFormat, usage);
 
         if (isRenderable) {
             ptr->AllowRBFormat(sizedFormat, usage);
         }
     };
 
 #define FOO(x) LOCAL_GL_ ## x, EffectiveFormat::x
@@ -836,17 +943,17 @@ FormatUsageAuthority::CreateForWebGL2(gl
 #endif
 #undef FOO
 
     // GLES 3.0.4, p206, "Required Renderbuffer Formats":
     // "Implementations are also required to support STENCIL_INDEX8. Requesting this
     //  internal format for a renderbuffer will allocate at least 8 stencil bit planes."
 
     auto usage = ptr->EditUsage(EffectiveFormat::STENCIL_INDEX8);
-    usage->isRenderable = true;
+    usage->SetRenderable();
     ptr->AllowRBFormat(LOCAL_GL_STENCIL_INDEX8, usage);
 
     ////////////////
     // Legacy formats
 
     if (!AddUnsizedFormats(ptr, gl))
         return nullptr;
 
@@ -856,16 +963,18 @@ FormatUsageAuthority::CreateForWebGL2(gl
     if (gfxPrefs::WebGL2CompatMode()) {
         AddSimpleUnsized(ptr, LOCAL_GL_RGBA, LOCAL_GL_FLOAT, EffectiveFormat::RGBA32F);
         AddSimpleUnsized(ptr, LOCAL_GL_RGB , LOCAL_GL_FLOAT, EffectiveFormat::RGB32F );
 
         AddSimpleUnsized(ptr, LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::RGBA16F);
         AddSimpleUnsized(ptr, LOCAL_GL_RGB , LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::RGB16F );
     }
 
+    ////////////////////////////////////
+
     return Move(ret);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 void
 FormatUsageAuthority::AddTexUnpack(FormatUsageInfo* usage, const PackingInfo& pi,
                                    const DriverUnpackInfo& dui)
@@ -904,17 +1013,17 @@ FormatUsageAuthority::AreUnpackEnumsVali
 
 ////////////////////
 
 void
 FormatUsageAuthority::AllowRBFormat(GLenum sizedFormat, const FormatUsageInfo* usage)
 {
     MOZ_ASSERT(!usage->format->compression);
     MOZ_ASSERT(usage->format->sizedFormat);
-    MOZ_ASSERT(usage->isRenderable);
+    MOZ_ASSERT(usage->IsRenderable());
 
     AlwaysInsert(mRBFormatMap, sizedFormat, usage);
 }
 
 void
 FormatUsageAuthority::AllowSizedTexFormat(GLenum sizedFormat,
                                           const FormatUsageInfo* usage)
 {
--- a/dom/canvas/WebGLFormats.h
+++ b/dom/canvas/WebGLFormats.h
@@ -206,17 +206,19 @@ struct FormatInfo
     const bool isColorFormat;             // memory usage estimation. Use
     const bool isSRGB;                    // BytesPerPixel(packingFormat, packingType) for
     const bool hasAlpha;                  // calculating pack/unpack byte count.
     const bool hasDepth;
     const bool hasStencil;
 
     const CompressedFormatInfo* const compression;
 
-    map<GLenum, const FormatInfo*> copyFormats;
+    std::map<UnsizedFormat, const FormatInfo*> copyDecayFormats;
+
+    const FormatInfo* GetCopyDecayFormat(UnsizedFormat) const;
 };
 
 struct PackingInfo
 {
     GLenum format;
     GLenum type;
 
     bool operator <(const PackingInfo& x) const
@@ -247,17 +249,19 @@ uint8_t BytesPerPixel(const PackingInfo&
 GLint ComponentSize(const FormatInfo* format, GLenum component);
 GLenum ComponentType(const FormatInfo* format);
 */
 ////////////////////////////////////////
 
 struct FormatUsageInfo
 {
     const FormatInfo* const format;
+private:
     bool isRenderable;
+public:
     bool isFilterable;
 
     std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
     const DriverUnpackInfo* idealUnpack;
 
     const GLint* textureSwizzleRGBA;
 
     bool maxSamplesKnown;
@@ -272,16 +276,19 @@ struct FormatUsageInfo
         , isRenderable(false)
         , isFilterable(false)
         , idealUnpack(nullptr)
         , textureSwizzleRGBA(nullptr)
         , maxSamplesKnown(false)
         , maxSamples(0)
     { }
 
+    bool IsRenderable() const { return isRenderable; }
+    void SetRenderable();
+
     bool IsUnpackValid(const PackingInfo& key,
                        const DriverUnpackInfo** const out_value) const;
 
     void ResolveMaxSamples(gl::GLContext* gl);
 };
 
 class FormatUsageAuthority
 {