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 &params, 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