1 /*
2  *  libacryl_plugins/libacryl_hdr_plugin.cpp
3  *
4  *   Copyright 2020 Samsung Electronics Co., Ltd.
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18 #include <cassert>
19 #include <array>
20 
21 #include <gs101/displaycolor/displaycolor_gs101.h>
22 #include <hardware/exynos/g2d_hdr_plugin.h>
23 
24 #define HDR_BASE 0x3000
25 #define HDR_SFR_LEN 0x800
26 
27 #define HDR_COM_CTRL 0x3004 // [0] HDR enable
28 static const uint32_t VAL_HDR_CTRL_ENABLE = 1;
29 
30 #define HDR_MOD_CTRL_NUM  1   // [0] oetf enable, [1] eotf enable [2] gm enable [5] tm enable
31 #define HDR_OETF_POSX_NUM 17  // two 16-bit from LSB
32 #define HDR_OETF_POSY_NUM 17  // two 10-bit from LSB
33 #define HDR_EOTF_POSX_NUM 65  // two 10-bit from LSB
34 #define HDR_EOTF_POSY_NUM 129 // one 16-bit
35 #define HDR_GM_COEF_NUM   9   // one 19-bit
36 #define HDR_GM_OFF_NUM    3   // one 17-bit
37 #define HDR_TM_COEF_NUM   1   // three 10-bit from LSB (R, G, B)
38 #define HDR_TM_RNGX_NUM   1   // two 16-bit from LSB (min:max)
39 #define HDR_TM_RNGY_NUM   1   // two 9-bit from LSB (min:max)
40 #define HDR_TM_POSX_NUM   17  // two 16-bit from LSB
41 #define HDR_TM_POSY_NUM   33  // one 27-bit from LSB
42 
43 #define HDR_MOD_CTRL_OFFSET  (0x8)
44 static const uint32_t HDR_ENABLE_OETF = 1 << 0;
45 static const uint32_t HDR_ENABLE_EOTF = 1 << 1;
46 static const uint32_t HDR_ENABLE_GM   = 1 << 2;
47 static const uint32_t HDR_ENABLE_DTM  = 1 << 5;
48 
49 #define HDR_OETF_POSX_OFFSET (HDR_MOD_CTRL_OFFSET  + 4 * HDR_MOD_CTRL_NUM )
50 #define HDR_OETF_POSY_OFFSET (HDR_OETF_POSX_OFFSET + 4 * HDR_OETF_POSX_NUM)
51 #define HDR_EOTF_POSX_OFFSET (HDR_OETF_POSY_OFFSET + 4 * HDR_OETF_POSY_NUM)
52 #define HDR_EOTF_POSY_OFFSET (HDR_EOTF_POSX_OFFSET + 4 * HDR_EOTF_POSX_NUM)
53 #define HDR_GM_COEF_OFFSET   (HDR_EOTF_POSY_OFFSET + 4 * HDR_EOTF_POSY_NUM)
54 #define HDR_GM_OFF_OFFSET    (HDR_GM_COEF_OFFSET   + 4 * HDR_GM_COEF_NUM  )
55 #define HDR_TM_COEF_OFFSET   (HDR_GM_OFF_OFFSET    + 4 * HDR_GM_OFF_NUM   )
56 #define HDR_TM_RNGX_OFFSET   (HDR_TM_COEF_OFFSET   + 4 * HDR_TM_COEF_NUM  )
57 #define HDR_TM_RNGY_OFFSET   (HDR_TM_RNGX_OFFSET   + 4 * HDR_TM_RNGX_NUM  )
58 #define HDR_TM_POSX_OFFSET   (HDR_TM_RNGY_OFFSET   + 4 * HDR_TM_RNGY_NUM  )
59 #define HDR_TM_POSY_OFFSET   (HDR_TM_POSX_OFFSET   + 4 * HDR_TM_POSX_NUM  )
60 
61 #define HDR_LAYER_BASE(layer) (HDR_BASE + HDR_SFR_LEN * (layer))
62 
63 #define HDR_MOD_CTRL(layer)  (HDR_LAYER_BASE(layer) + HDR_MOD_CTRL_OFFSET )
64 #define HDR_OETF_POSX(layer) (HDR_LAYER_BASE(layer) + HDR_OETF_POSX_OFFSET)
65 #define HDR_OETF_POSY(layer) (HDR_LAYER_BASE(layer) + HDR_OETF_POSY_OFFSET)
66 #define HDR_EOTF_POSX(layer) (HDR_LAYER_BASE(layer) + HDR_EOTF_POSX_OFFSET)
67 #define HDR_EOTF_POSY(layer) (HDR_LAYER_BASE(layer) + HDR_EOTF_POSY_OFFSET)
68 #define HDR_GM_COEF(layer)   (HDR_LAYER_BASE(layer) + HDR_GM_COEF_OFFSET  )
69 #define HDR_GM_OFF(layer)    (HDR_LAYER_BASE(layer) + HDR_GM_OFF_OFFSET   )
70 #define HDR_TM_COEF(layer)   (HDR_LAYER_BASE(layer) + HDR_TM_COEF_OFFSET  )
71 #define HDR_TM_RNGX(layer)   (HDR_LAYER_BASE(layer) + HDR_TM_RNGX_OFFSET  )
72 #define HDR_TM_RNGY(layer)   (HDR_LAYER_BASE(layer) + HDR_TM_RNGY_OFFSET  )
73 #define HDR_TM_POSX(layer)   (HDR_LAYER_BASE(layer) + HDR_TM_POSX_OFFSET  )
74 #define HDR_TM_POSY(layer)   (HDR_LAYER_BASE(layer) + HDR_TM_POSY_OFFSET  )
75 
76 #define G2D_LAYER_HDRMODE(i) (0x290 + (i) * 0x100)
77 
78 #define MAX_LAYER_COUNT 4
79 #define HDR_LAYER_SFR_COUNT (\
80       HDR_MOD_CTRL_NUM + HDR_OETF_POSX_NUM + HDR_OETF_POSY_NUM + \
81       HDR_EOTF_POSX_NUM + HDR_EOTF_POSY_NUM + HDR_GM_COEF_NUM + \
82       HDR_GM_OFF_NUM + HDR_TM_COEF_NUM + HDR_TM_RNGX_NUM + \
83       HDR_TM_RNGY_NUM + HDR_TM_POSX_NUM + HDR_TM_POSY_NUM\
84       )
85 
86 static const size_t NUM_HDR_COEFFICIENTS = HDR_LAYER_SFR_COUNT * MAX_LAYER_COUNT + 1; // HDR SFR COUNT x LAYER COUNT + COM_CTRL
87 static const size_t NUM_HDR_MODE_REGS = MAX_LAYER_COUNT;
88 
89 class G2DHdrCommandWriter: public IG2DHdr10CommandWriter {
90     std::bitset<MAX_LAYER_COUNT> mLayerAlphaMap;
91     std::array<displaycolor::IDisplayColorGS101::IDpp *, MAX_LAYER_COUNT> mLayerData{};
92 
93 public:
94     struct CommandList {
95         std::array<g2d_reg, NUM_HDR_COEFFICIENTS> commands;     // (294 * 4 + 1) * 8 bytes
96         std::array<g2d_reg, NUM_HDR_MODE_REGS> layer_hdr_modes; // 4 * 8 bytes
97         g2d_commandlist cmdlist{};
98 
CommandListG2DHdrCommandWriter::CommandList99         CommandList() {
100             cmdlist.commands = commands.data();
101             cmdlist.layer_hdr_mode = layer_hdr_modes.data();
102         }
103 
~CommandListG2DHdrCommandWriter::CommandList104         ~CommandList() { }
105 
resetG2DHdrCommandWriter::CommandList106         void reset() {
107             cmdlist.command_count = 0;
108             cmdlist.layer_count = 0;
109         }
110 
getG2DHdrCommandWriter::CommandList111         g2d_commandlist *get() { return &cmdlist; }
112 
set_and_get_next_offsetG2DHdrCommandWriter::CommandList113         uint32_t set_and_get_next_offset(uint32_t offset, uint32_t value) {
114             commands[cmdlist.command_count].offset = offset;
115             commands[cmdlist.command_count].value = value;
116             cmdlist.command_count++;
117             return offset + sizeof(value);
118         }
119 
updateLayerG2DHdrCommandWriter::CommandList120         void updateLayer(std::size_t layer, bool alpha_premultiplied, uint32_t modectl) {
121             auto &hdr_mode = layer_hdr_modes[cmdlist.layer_count++];
122 
123             hdr_mode.offset = G2D_LAYER_HDRMODE(layer);
124             hdr_mode.value = layer;
125             // The premultiplied alpha should be demultiplied before HDR conversion.
126             if (alpha_premultiplied)
127                 hdr_mode.value |= G2D_LAYER_HDRMODE_DEMULT_ALPHA;
128 
129             set_and_get_next_offset(HDR_MOD_CTRL(layer), modectl);
130         }
131 
132         template <typename containerT>
updateDoubleG2DHdrCommandWriter::CommandList133         void updateDouble(const containerT &container, uint32_t offset) {
134             for (std::size_t n = 0; n < container.size(); n += 2)
135                 offset = set_and_get_next_offset(offset, container[n] | container[n + 1] << 16);
136             if ((container.size() % 2) == 1)
137                 set_and_get_next_offset(offset, container.back());
138         }
139 
140         template <typename containerT>
updateSingleG2DHdrCommandWriter::CommandList141         void updateSingle(const containerT &container, uint32_t offset) {
142             for (auto item : container)
143                 offset = set_and_get_next_offset(offset, item);
144         }
145 
updateTmCoefG2DHdrCommandWriter::CommandList146         void updateTmCoef(const displaycolor::IDisplayColorGS101::IDpp::DtmData::ConfigType &config, uint32_t offset) {
147             offset = set_and_get_next_offset(offset, config.coeff_r | (config.coeff_g << 10) | (config.coeff_b << 20));
148             offset = set_and_get_next_offset(offset, config.rng_x_min | (config.rng_x_max << 16));
149             set_and_get_next_offset(offset, config.rng_y_min | (config.rng_y_max << 16));
150         }
151 
updateHdrG2DHdrCommandWriter::CommandList152         void updateHdr() {
153             if (cmdlist.command_count > 0)
154                 set_and_get_next_offset(HDR_COM_CTRL, VAL_HDR_CTRL_ENABLE);
155         }
156     } mCmdList;
157 
G2DHdrCommandWriter()158     G2DHdrCommandWriter() { }
~G2DHdrCommandWriter()159     virtual ~G2DHdrCommandWriter() { }
160 
setLayerStaticMetadata(int __unused index,int __unused dataspace,unsigned int __unused min_luminance,unsigned int __unused max_luminance)161     virtual bool setLayerStaticMetadata(int __unused index, int __unused dataspace,
162                                 unsigned int __unused min_luminance, unsigned int __unused max_luminance) override {
163         return true;
164     }
165 
setLayerImageInfo(int index,unsigned int __unused pixfmt,bool alpha_premult)166     virtual bool setLayerImageInfo(int index, unsigned int __unused pixfmt, bool alpha_premult) override {
167         if (alpha_premult)
168             mLayerAlphaMap.set(index);
169         return true;
170     }
171 
setTargetInfo(int __unused dataspace,void * __unused data)172     virtual bool setTargetInfo(int __unused dataspace, void * __unused data) override {
173         return true;
174     }
175 
setLayerOpaqueData(int index,void * data,size_t __unused len)176     virtual bool setLayerOpaqueData(int index, void *data, size_t __unused len) override {
177         mLayerData[index] = reinterpret_cast<displaycolor::IDisplayColorGS101::IDpp *>(data);
178         return true;
179     }
180 
getCommands()181     virtual struct g2d_commandlist *getCommands() override {
182         mCmdList.reset();
183 
184         unsigned int i = 0;
185         for (auto layer : mLayerData) {
186             if (layer) {
187                 uint32_t modectl = 0;
188 
189                 if (layer->EotfLut().enable && layer->EotfLut().config != nullptr) {
190                     mCmdList.updateDouble(layer->EotfLut().config->tf_data.posx, HDR_EOTF_POSX(i));
191                     mCmdList.updateSingle(layer->EotfLut().config->tf_data.posy, HDR_EOTF_POSY(i));
192                     modectl |= HDR_ENABLE_EOTF;
193                 }
194 
195                 if (layer->Gm().enable && layer->Gm().config != nullptr) {
196                     mCmdList.updateSingle(layer->Gm().config->matrix_data.coeffs, HDR_GM_COEF(i));
197                     mCmdList.updateSingle(layer->Gm().config->matrix_data.offsets, HDR_GM_OFF(i));
198                     modectl |= HDR_ENABLE_GM;
199                 }
200 
201                 if (layer->Dtm().enable && layer->Dtm().config != nullptr) {
202                     mCmdList.updateTmCoef(*layer->Dtm().config, HDR_TM_COEF(i));
203                     mCmdList.updateDouble(layer->Dtm().config->tf_data.posx, HDR_TM_POSX(i));
204                     mCmdList.updateSingle(layer->Dtm().config->tf_data.posy, HDR_TM_POSY(i));
205                     modectl |= HDR_ENABLE_DTM;
206                 }
207 
208                 if (layer->OetfLut().enable && layer->OetfLut().config != nullptr) {
209                     mCmdList.updateDouble(layer->OetfLut().config->tf_data.posx, HDR_OETF_POSX(i));
210                     mCmdList.updateDouble(layer->OetfLut().config->tf_data.posy, HDR_OETF_POSY(i));
211                     modectl |= HDR_ENABLE_OETF;
212                 }
213 
214                 mCmdList.updateLayer(i, mLayerAlphaMap[0], modectl);
215             }
216 
217             mLayerAlphaMap >>= 1;
218             i++;
219         }
220 
221         mCmdList.updateHdr();
222 
223         // initialize for the next layer metadata configuration
224         mLayerAlphaMap.reset();
225         mLayerData.fill(nullptr);
226 
227         return mCmdList.get();
228     }
229 
putCommands(struct g2d_commandlist __unused * commands)230     virtual void putCommands(struct g2d_commandlist __unused *commands) override {
231         assert(commands == &mCommandList);
232     }
233 };
234 
createInstance()235 IG2DHdr10CommandWriter *IG2DHdr10CommandWriter::createInstance() {
236     return new G2DHdrCommandWriter();
237 }
238