1 #include <array>
2 #include <memory>
3 #include "common/cpuinfo.h"
4 #include "common/except.h"
5 #include "common/make_unique.h"
6 #include "common/pixel.h"
7 #include "common/zassert.h"
8 #include "graph/basic_filter.h"
9 #include "graph/image_filter.h"
10 #include "colorspace.h"
11 #include "graph.h"
12 #include "operation.h"
13
14 namespace zimg {
15 namespace colorspace {
16
17 namespace {
18
19 class ColorspaceConversionImpl final : public graph::ImageFilterBase {
20 std::array<std::unique_ptr<Operation>, 6> m_operations;
21 unsigned m_width;
22 unsigned m_height;
23 public:
ColorspaceConversionImpl(unsigned width,unsigned height,const ColorspaceDefinition & in,const ColorspaceDefinition & out,const OperationParams & params,CPUClass cpu)24 ColorspaceConversionImpl(unsigned width, unsigned height, const ColorspaceDefinition &in, const ColorspaceDefinition &out,
25 const OperationParams ¶ms, CPUClass cpu) :
26 m_width{ width },
27 m_height{ height }
28 {
29 zassert_d(width <= pixel_max_width(PixelType::FLOAT), "overflow");
30
31 auto path = get_operation_path(in, out);
32 zassert(!path.empty(), "empty path");
33 zassert(path.size() <= 6, "too many operations");
34
35 for (size_t i = 0; i < path.size(); ++i) {
36 m_operations[i] = path[i](params, cpu);
37 }
38 }
39
get_flags() const40 filter_flags get_flags() const override
41 {
42 filter_flags flags{};
43
44 flags.same_row = true;
45 flags.in_place = true;
46 flags.color = true;
47
48 return flags;
49 }
50
get_image_attributes() const51 image_attributes get_image_attributes() const override
52 {
53 return{ m_width, m_height, PixelType::FLOAT };
54 }
55
process(void *,const graph::ImageBuffer<const void> src[],const graph::ImageBuffer<void> dst[],void *,unsigned i,unsigned left,unsigned right) const56 void process(void *, const graph::ImageBuffer<const void> src[], const graph::ImageBuffer<void> dst[], void *, unsigned i, unsigned left, unsigned right) const override
57 {
58 const float *src_ptr[3];
59 float *dst_ptr[3];
60
61 for (unsigned p = 0; p < 3; ++p) {
62 src_ptr[p] = static_cast<const float *>(src[p][i]);
63 dst_ptr[p] = static_cast<float *>(dst[p][i]);
64 }
65
66 m_operations[0]->process(src_ptr, dst_ptr, left, right);
67
68 if (!m_operations[1])
69 return;
70 m_operations[1]->process(dst_ptr, dst_ptr, left, right);
71
72 if (!m_operations[2])
73 return;
74 m_operations[2]->process(dst_ptr, dst_ptr, left, right);
75
76 if (!m_operations[3])
77 return;
78 m_operations[3]->process(dst_ptr, dst_ptr, left, right);
79
80 if (!m_operations[4])
81 return;
82 m_operations[4]->process(dst_ptr, dst_ptr, left, right);
83
84 if (!m_operations[5])
85 return;
86 m_operations[5]->process(dst_ptr, dst_ptr, left, right);
87 }
88 };
89
90 } // namespace
91
92
ColorspaceConversion(unsigned width,unsigned height)93 ColorspaceConversion::ColorspaceConversion(unsigned width, unsigned height) :
94 width{ width },
95 height{ height },
96 csp_in{},
97 csp_out{},
98 peak_luminance{ 100.0 },
99 approximate_gamma{},
100 scene_referred{},
101 cpu{ CPUClass::NONE }
102 {}
103
create() const104 std::unique_ptr<graph::ImageFilter> ColorspaceConversion::create() const try
105 {
106 OperationParams params;
107 params.set_peak_luminance(peak_luminance)
108 .set_approximate_gamma(approximate_gamma)
109 .set_scene_referred(scene_referred);
110
111 if (csp_in == csp_out)
112 return ztd::make_unique<graph::CopyFilter>(width, height, PixelType::FLOAT, true);
113 else
114 return ztd::make_unique<ColorspaceConversionImpl>(width, height, csp_in, csp_out, params, cpu);
115 } catch (const std::bad_alloc &) {
116 error::throw_<error::OutOfMemory>();
117 }
118
119 } // namespace colorspace
120 } // namespace zimg
121