154f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman/*
254f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman * Copyright 2016 Google Inc.
354f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman *
454f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman * Use of this source code is governed by a BSD-style license that can be
554f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman * found in the LICENSE file.
654f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman */
754f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman
854f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman#ifndef GrColorSpaceXform_DEFINED
954f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman#define GrColorSpaceXform_DEFINED
1054f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman
115a7ae7e337a68dc42723fce80752c93b7d26d469brianosman#include "GrColor.h"
12c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman#include "GrFragmentProcessor.h"
13f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman#include "SkColorSpace.h"
145192475bd8cb98e8e0c1192ab5ece7b8595701d6brianosman#include "SkMatrix44.h"
1554f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman#include "SkRefCnt.h"
1654f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman
1754f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman /**
18f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman  * Represents a color space transformation
1954f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman  */
2054f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosmanclass GrColorSpaceXform : public SkRefCnt {
2154f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosmanpublic:
22f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    GrColorSpaceXform(const SkColorSpaceTransferFn&, const SkMatrix44&, uint32_t);
23f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman
24f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    static sk_sp<GrColorSpaceXform> Make(const SkColorSpace* src,
25f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman                                         GrPixelConfig srcConfig,
26f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman                                         const SkColorSpace* dst);
27f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    static sk_sp<GrColorSpaceXform> MakeGamutXform(const SkColorSpace* src,
28f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman                                                   const SkColorSpace* dst) {
29f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        auto result = Make(src, kUnknown_GrPixelConfig, dst);
30f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        SkASSERT(!result || 0 == (result->fFlags & ~kApplyGamutXform_Flag));
31f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        return result;
32f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    }
3354f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman
34f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    const SkColorSpaceTransferFn& transferFn() const { return fSrcTransferFn; }
35f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    const float* transferFnCoeffs() const {
36f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        static_assert(0 == offsetof(SkColorSpaceTransferFn, fG), "TransferFn layout");
37f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        return &fSrcTransferFn.fG;
38f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    }
3954f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman
40f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    const SkMatrix44& gamutXform() const { return fGamutXform; }
4177320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman
4277320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    /**
4377320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman     * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in its
4477320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman     * computed key.
4577320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman     */
46e411a077ec2cc018351d92e668def5da6905e4ecBrian Osman    static uint32_t XformKey(const GrColorSpaceXform* xform) {
47f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        // Code generation depends on which steps we apply (as encoded by fFlags)
48f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        return SkToBool(xform) ? xform->fFlags : 0;
4977320dbabcddf05c0a1489eaf1f496729dc8de0ebrianosman    }
5054f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman
51b9c5137a1cedbe8a3641db0b7c081881a2d5d58cbrianosman    static bool Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b);
52b9c5137a1cedbe8a3641db0b7c081881a2d5d58cbrianosman
53fe3e858e751609c3a9cbf7ad710ed415ea7213fcBrian Osman    GrColor4f unclampedXform(const GrColor4f& srcColor);
54fe3e858e751609c3a9cbf7ad710ed415ea7213fcBrian Osman    GrColor4f clampedXform(const GrColor4f& srcColor);
555a7ae7e337a68dc42723fce80752c93b7d26d469brianosman
5654f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosmanprivate:
57f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    friend class GrGLSLColorSpaceXformHelper;
58f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman
59f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    enum Flags {
60f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        kApplyTransferFn_Flag = 0x1,
61f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        kApplyGamutXform_Flag = 0x2,
62f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman
63f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        // Almost never used. This handles the case where the src data is sRGB pixel config,
64f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        // but the color space has a different transfer function. In that case, we first undo
65f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        // the HW sRGB -> Linear conversion, before applying any other steps.
66f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman        kApplyInverseSRGB_Flag = 0x4,
67f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    };
68f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman
69f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    SkColorSpaceTransferFn fSrcTransferFn;
70f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    SkMatrix44 fGamutXform;
71f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman    uint32_t fFlags;
7254f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman};
7354f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman
74c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osmanclass GrColorSpaceXformEffect : public GrFragmentProcessor {
75c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osmanpublic:
76c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    /**
77c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman     *  Returns a fragment processor that calls the passed in fragment processor, and then converts
78c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman     *  the color space of the output from src to dst.
79c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman     */
80c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child,
81c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman                                                     const SkColorSpace* src,
82f06ead925c631c42fae734de1e7c72237a2e91f4Brian Osman                                                     GrPixelConfig srcConfig,
83c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman                                                     const SkColorSpace* dst);
84c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
85c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    const char* name() const override { return "ColorSpaceXform"; }
86c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    std::unique_ptr<GrFragmentProcessor> clone() const override;
87c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
88c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    const GrColorSpaceXform* colorXform() const { return fColorXform.get(); }
89c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
90c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osmanprivate:
91c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
92c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman                            sk_sp<GrColorSpaceXform> colorXform);
93c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
94c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    static OptimizationFlags OptFlags(const GrFragmentProcessor* child);
95c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
96c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
97c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
98c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    bool onIsEqual(const GrFragmentProcessor&) const override;
99c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
100c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    sk_sp<GrColorSpaceXform> fColorXform;
101c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
102c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman    typedef GrFragmentProcessor INHERITED;
103c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman};
104c4f93cab667b022bbaa196bddcbca23592ad2e6cBrian Osman
10554f30c13fc0a5d89797fc9be5f0fb1050d96b6f4brianosman#endif
106