1 // Copyright 2014 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <array>
8 #include <memory>
9 #include <string>
10 #include <boost/serialization/array.hpp>
11 #include "common/common_types.h"
12 #include "core/hle/result.h"
13 #include "core/hle/service/service.h"
14 
15 namespace Core {
16 class System;
17 }
18 
19 namespace Kernel {
20 class Event;
21 }
22 
23 namespace Service::Y2R {
24 
25 enum class InputFormat : u8 {
26     /// 8-bit input, with YUV components in separate planes and 4:2:2 subsampling.
27     YUV422_Indiv8 = 0,
28     /// 8-bit input, with YUV components in separate planes and 4:2:0 subsampling.
29     YUV420_Indiv8 = 1,
30 
31     /// 16-bit input (only LSB used), with YUV components in separate planes and 4:2:2 subsampling.
32     YUV422_Indiv16 = 2,
33     /// 16-bit input (only LSB used), with YUV components in separate planes and 4:2:0 subsampling.
34     YUV420_Indiv16 = 3,
35 
36     /// 8-bit input, with a single interleaved stream in YUYV format and 4:2:2 subsampling.
37     YUYV422_Interleaved = 4,
38 };
39 
40 enum class OutputFormat : u8 {
41     RGBA8 = 0,
42     RGB8 = 1,
43     RGB5A1 = 2,
44     RGB565 = 3,
45 };
46 
47 enum class Rotation : u8 {
48     None = 0,
49     Clockwise_90 = 1,
50     Clockwise_180 = 2,
51     Clockwise_270 = 3,
52 };
53 
54 enum class BlockAlignment : u8 {
55     /// Image is output in linear format suitable for use as a framebuffer.
56     Linear = 0,
57     /// Image is output in tiled PICA format, suitable for use as a texture.
58     Block8x8 = 1,
59 };
60 
61 enum class StandardCoefficient : u8 {
62     /// ITU Rec. BT.601 primaries, with PC ranges.
63     ITU_Rec601 = 0,
64     /// ITU Rec. BT.709 primaries, with PC ranges.
65     ITU_Rec709 = 1,
66     /// ITU Rec. BT.601 primaries, with TV ranges.
67     ITU_Rec601_Scaling = 2,
68     /// ITU Rec. BT.709 primaries, with TV ranges.
69     ITU_Rec709_Scaling = 3,
70 };
71 
72 /**
73  * A set of coefficients configuring the RGB to YUV conversion. Coefficients 0-4 are unsigned 2.8
74  * fixed pointer numbers representing entries on the conversion matrix, while coefficient 5-7 are
75  * signed 11.5 fixed point numbers added as offsets to the RGB result.
76  *
77  * The overall conversion process formula is:
78  * ```
79  * R = trunc((c_0 * Y           + c_1 * V) + c_5 + 0.75)
80  * G = trunc((c_0 * Y - c_3 * U - c_2 * V) + c_6 + 0.75)
81  * B = trunc((c_0 * Y + c_4 * U          ) + c_7 + 0.75)
82  * ```
83  */
84 using CoefficientSet = std::array<s16, 8>;
85 
86 struct ConversionBuffer {
87     /// Current reading/writing address of this buffer.
88     VAddr address;
89     /// Remaining amount of bytes to be DMAed, does not include the inter-trasfer gap.
90     u32 image_size;
91     /// Size of a single DMA transfer.
92     u16 transfer_unit;
93     /// Amount of bytes to be skipped between copying each `transfer_unit` bytes.
94     u16 gap;
95 
96 private:
97     template <class Archive>
serializeConversionBuffer98     void serialize(Archive& ar, const unsigned int) {
99         ar& address;
100         ar& image_size;
101         ar& transfer_unit;
102         ar& gap;
103     }
104     friend class boost::serialization::access;
105 };
106 
107 struct ConversionConfiguration {
108     InputFormat input_format;
109     OutputFormat output_format;
110     Rotation rotation;
111     BlockAlignment block_alignment;
112     u16 input_line_width;
113     u16 input_lines;
114     CoefficientSet coefficients;
115     u8 padding;
116     u16 alpha;
117 
118     /// Input parameters for the Y (luma) plane
119     ConversionBuffer src_Y, src_U, src_V, src_YUYV;
120     /// Output parameters for the conversion results
121     ConversionBuffer dst;
122 
123     ResultCode SetInputLineWidth(u16 width);
124     ResultCode SetInputLines(u16 lines);
125     ResultCode SetStandardCoefficient(StandardCoefficient standard_coefficient);
126 
127 private:
128     template <class Archive>
serializeConversionConfiguration129     void serialize(Archive& ar, const unsigned int) {
130         ar& input_format;
131         ar& output_format;
132         ar& rotation;
133         ar& block_alignment;
134         ar& input_line_width;
135         ar& input_lines;
136         ar& coefficients;
137         ar& padding;
138         ar& alpha;
139         ar& src_Y;
140         ar& src_U;
141         ar& src_V;
142         ar& src_YUYV;
143         ar& dst;
144     }
145     friend class boost::serialization::access;
146 };
147 
148 struct DitheringWeightParams {
149     u16 w0_xEven_yEven;
150     u16 w0_xOdd_yEven;
151     u16 w0_xEven_yOdd;
152     u16 w0_xOdd_yOdd;
153     u16 w1_xEven_yEven;
154     u16 w1_xOdd_yEven;
155     u16 w1_xEven_yOdd;
156     u16 w1_xOdd_yOdd;
157     u16 w2_xEven_yEven;
158     u16 w2_xOdd_yEven;
159     u16 w2_xEven_yOdd;
160     u16 w2_xOdd_yOdd;
161     u16 w3_xEven_yEven;
162     u16 w3_xOdd_yEven;
163     u16 w3_xEven_yOdd;
164     u16 w3_xOdd_yOdd;
165 
166 private:
167     template <class Archive>
serializeDitheringWeightParams168     void serialize(Archive& ar, const unsigned int) {
169         ar& w0_xEven_yEven;
170         ar& w0_xOdd_yEven;
171         ar& w0_xEven_yOdd;
172         ar& w0_xOdd_yOdd;
173         ar& w1_xEven_yEven;
174         ar& w1_xOdd_yEven;
175         ar& w1_xEven_yOdd;
176         ar& w1_xOdd_yOdd;
177         ar& w2_xEven_yEven;
178         ar& w2_xOdd_yEven;
179         ar& w2_xEven_yOdd;
180         ar& w2_xOdd_yOdd;
181         ar& w3_xEven_yEven;
182         ar& w3_xOdd_yEven;
183         ar& w3_xEven_yOdd;
184         ar& w3_xOdd_yOdd;
185     }
186     friend class boost::serialization::access;
187 };
188 
189 struct ConversionParameters {
190     InputFormat input_format;
191     OutputFormat output_format;
192     Rotation rotation;
193     BlockAlignment block_alignment;
194     u16 input_line_width;
195     u16 input_lines;
196     StandardCoefficient standard_coefficient;
197     u8 padding;
198     u16 alpha;
199 };
200 static_assert(sizeof(ConversionParameters) == 12, "ConversionParameters struct has incorrect size");
201 
202 class Y2R_U final : public ServiceFramework<Y2R_U> {
203 public:
204     explicit Y2R_U(Core::System& system);
205     ~Y2R_U() override;
206 
207 private:
208     void SetInputFormat(Kernel::HLERequestContext& ctx);
209     void GetInputFormat(Kernel::HLERequestContext& ctx);
210     void SetOutputFormat(Kernel::HLERequestContext& ctx);
211     void GetOutputFormat(Kernel::HLERequestContext& ctx);
212     void SetRotation(Kernel::HLERequestContext& ctx);
213     void GetRotation(Kernel::HLERequestContext& ctx);
214     void SetBlockAlignment(Kernel::HLERequestContext& ctx);
215     void GetBlockAlignment(Kernel::HLERequestContext& ctx);
216 
217     /**
218      * Y2R_U::SetSpacialDithering service function
219      *  Inputs:
220      *      1 : u8, 0 = Disabled, 1 = Enabled
221      *  Outputs:
222      *      1 : Result of function, 0 on success, otherwise error code
223      */
224     void SetSpacialDithering(Kernel::HLERequestContext& ctx);
225 
226     /**
227      * Y2R_U::GetSpacialDithering service function
228      *  Outputs:
229      *      1 : Result of function, 0 on success, otherwise error code
230      *      2 : u8, 0 = Disabled, 1 = Enabled
231      */
232     void GetSpacialDithering(Kernel::HLERequestContext& ctx);
233 
234     /**
235      * Y2R_U::SetTemporalDithering service function
236      *  Inputs:
237      *      1 : u8, 0 = Disabled, 1 = Enabled
238      *  Outputs:
239      *      1 : Result of function, 0 on success, otherwise error code
240      */
241     void SetTemporalDithering(Kernel::HLERequestContext& ctx);
242 
243     /**
244      * Y2R_U::GetTemporalDithering service function
245      *  Outputs:
246      *      1 : Result of function, 0 on success, otherwise error code
247      *      2 : u8, 0 = Disabled, 1 = Enabled
248      */
249     void GetTemporalDithering(Kernel::HLERequestContext& ctx);
250 
251     /**
252      * Y2R_U::SetTransferEndInterrupt service function
253      *  Inputs:
254      *      1 : u8, 0 = Disabled, 1 = Enabled
255      *  Outputs:
256      *      1 : Result of function, 0 on success, otherwise error code
257      */
258     void SetTransferEndInterrupt(Kernel::HLERequestContext& ctx);
259 
260     /**
261      * Y2R_U::GetTransferEndInterrupt service function
262      *  Outputs:
263      *      1 : Result of function, 0 on success, otherwise error code
264      *      2 : u8, 0 = Disabled, 1 = Enabled
265      */
266     void GetTransferEndInterrupt(Kernel::HLERequestContext& ctx);
267 
268     /**
269      * Y2R_U::GetTransferEndEvent service function
270      *  Outputs:
271      *      1 : Result of function, 0 on success, otherwise error code
272      *      3 : The handle of the completion event
273      */
274     void GetTransferEndEvent(Kernel::HLERequestContext& ctx);
275 
276     void SetSendingY(Kernel::HLERequestContext& ctx);
277     void SetSendingU(Kernel::HLERequestContext& ctx);
278     void SetSendingV(Kernel::HLERequestContext& ctx);
279     void SetSendingYUYV(Kernel::HLERequestContext& ctx);
280 
281     /**
282      * Y2R::IsFinishedSendingYuv service function
283      * Output:
284      *       1 : Result of the function, 0 on success, otherwise error code
285      *       2 : u8, 0 = Not Finished, 1 = Finished
286      */
287     void IsFinishedSendingYuv(Kernel::HLERequestContext& ctx);
288 
289     /**
290      * Y2R::IsFinishedSendingY service function
291      * Output:
292      *       1 : Result of the function, 0 on success, otherwise error code
293      *       2 : u8, 0 = Not Finished, 1 = Finished
294      */
295     void IsFinishedSendingY(Kernel::HLERequestContext& ctx);
296 
297     /**
298      * Y2R::IsFinishedSendingU service function
299      * Output:
300      *       1 : Result of the function, 0 on success, otherwise error code
301      *       2 : u8, 0 = Not Finished, 1 = Finished
302      */
303     void IsFinishedSendingU(Kernel::HLERequestContext& ctx);
304 
305     /**
306      * Y2R::IsFinishedSendingV service function
307      * Output:
308      *       1 : Result of the function, 0 on success, otherwise error code
309      *       2 : u8, 0 = Not Finished, 1 = Finished
310      */
311     void IsFinishedSendingV(Kernel::HLERequestContext& ctx);
312 
313     void SetReceiving(Kernel::HLERequestContext& ctx);
314 
315     /**
316      * Y2R::IsFinishedReceiving service function
317      * Output:
318      *       1 : Result of the function, 0 on success, otherwise error code
319      *       2 : u8, 0 = Not Finished, 1 = Finished
320      */
321     void IsFinishedReceiving(Kernel::HLERequestContext& ctx);
322 
323     void SetInputLineWidth(Kernel::HLERequestContext& ctx);
324     void GetInputLineWidth(Kernel::HLERequestContext& ctx);
325     void SetInputLines(Kernel::HLERequestContext& ctx);
326     void GetInputLines(Kernel::HLERequestContext& ctx);
327     void SetCoefficient(Kernel::HLERequestContext& ctx);
328     void GetCoefficient(Kernel::HLERequestContext& ctx);
329     void SetStandardCoefficient(Kernel::HLERequestContext& ctx);
330     void GetStandardCoefficient(Kernel::HLERequestContext& ctx);
331     void SetAlpha(Kernel::HLERequestContext& ctx);
332     void GetAlpha(Kernel::HLERequestContext& ctx);
333     void SetDitheringWeightParams(Kernel::HLERequestContext& ctx);
334     void GetDitheringWeightParams(Kernel::HLERequestContext& ctx);
335     void StartConversion(Kernel::HLERequestContext& ctx);
336     void StopConversion(Kernel::HLERequestContext& ctx);
337     void IsBusyConversion(Kernel::HLERequestContext& ctx);
338 
339     /**
340      * Y2R_U::SetPackageParameter service function
341      */
342     void SetPackageParameter(Kernel::HLERequestContext& ctx);
343 
344     void PingProcess(Kernel::HLERequestContext& ctx);
345     void DriverInitialize(Kernel::HLERequestContext& ctx);
346     void DriverFinalize(Kernel::HLERequestContext& ctx);
347     void GetPackageParameter(Kernel::HLERequestContext& ctx);
348 
349     Core::System& system;
350 
351     std::shared_ptr<Kernel::Event> completion_event;
352     ConversionConfiguration conversion{};
353     DitheringWeightParams dithering_weight_params{};
354     bool temporal_dithering_enabled = false;
355     bool transfer_end_interrupt_enabled = false;
356     bool spacial_dithering_enabled = false;
357 
358     template <class Archive>
359     void serialize(Archive& ar, const unsigned int);
360     friend class boost::serialization::access;
361 };
362 
363 void InstallInterfaces(Core::System& system);
364 
365 } // namespace Service::Y2R
366 
367 SERVICE_CONSTRUCT(Service::Y2R::Y2R_U)
368 BOOST_CLASS_EXPORT_KEY(Service::Y2R::Y2R_U)
369