Skip to content

Commit

Permalink
Replace functors with function pointers (#324)
Browse files Browse the repository at this point in the history
* Replace functors with function pointers during decoding

The functors were constructed on the heap and the actual implemenation was called using a virtual method call.
The main advantage of a functor (insert inline) could not be leveraged.
As a first step replace these functors with basic function pointers. It replaces a virtual call to a member function with a
function pointer call to a static method (no need to pass this pointer).

* Rename process_decoded_line.hpp in copy_from_line_buffer.hpp

* Replace functors with function pointers during encoding

The functors were constructed on the heap and the actual implementation was called using a virtual method call.
The main advantage of a functor (insert inline) could not be leveraged.
As a first step replace these functors with basic function pointers. It replaces a virtual call to a member function with a
function pointer call to a static method (no need to pass this pointer).

* Rename process_encoded_line.hpp to copy_to_line_buffer.hpp
  • Loading branch information
vbaderks authored Aug 26, 2024
1 parent bb71852 commit bbd2d34
Show file tree
Hide file tree
Showing 16 changed files with 446 additions and 547 deletions.
4 changes: 2 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ target_sources(charls
"${CMAKE_CURRENT_LIST_DIR}/color_transform.hpp"
"${CMAKE_CURRENT_LIST_DIR}/conditional_static_cast.hpp"
"${CMAKE_CURRENT_LIST_DIR}/constants.hpp"
"${CMAKE_CURRENT_LIST_DIR}/copy_from_line_buffer.hpp"
"${CMAKE_CURRENT_LIST_DIR}/copy_to_line_buffer.hpp"
"${CMAKE_CURRENT_LIST_DIR}/default_traits.hpp"
"${CMAKE_CURRENT_LIST_DIR}/golomb_lut.hpp"
"${CMAKE_CURRENT_LIST_DIR}/golomb_lut.cpp"
Expand All @@ -125,8 +127,6 @@ target_sources(charls
"${CMAKE_CURRENT_LIST_DIR}/lossless_traits.hpp"
"${CMAKE_CURRENT_LIST_DIR}/make_scan_codec.hpp"
"${CMAKE_CURRENT_LIST_DIR}/make_scan_codec.cpp"
"${CMAKE_CURRENT_LIST_DIR}/process_decoded_line.hpp"
"${CMAKE_CURRENT_LIST_DIR}/process_encoded_line.hpp"
"${CMAKE_CURRENT_LIST_DIR}/quantization_lut.hpp"
"${CMAKE_CURRENT_LIST_DIR}/quantization_lut.cpp"
"${CMAKE_CURRENT_LIST_DIR}/regular_mode_context.hpp"
Expand Down
4 changes: 2 additions & 2 deletions src/CharLS.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
<ClInclude Include="constants.hpp" />
<ClInclude Include="regular_mode_context.hpp" />
<ClInclude Include="run_mode_context.hpp" />
<ClInclude Include="process_encoded_line.hpp" />
<ClInclude Include="copy_to_line_buffer.hpp" />
<ClInclude Include="scan_decoder.hpp" />
<ClInclude Include="default_traits.hpp" />
<ClInclude Include="scan_encoder.hpp" />
Expand All @@ -256,7 +256,7 @@
<ClInclude Include="jpeg_stream_writer.hpp" />
<ClInclude Include="lossless_traits.hpp" />
<ClInclude Include="jpegls_preset_parameters_type.hpp" />
<ClInclude Include="process_decoded_line.hpp" />
<ClInclude Include="copy_from_line_buffer.hpp" />
<ClInclude Include="quantization_lut.hpp" />
<ClInclude Include="scan_decoder_impl.hpp" />
<ClInclude Include="scan_encoder_impl.hpp" />
Expand Down
4 changes: 2 additions & 2 deletions src/CharLS.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@
<ClInclude Include="make_scan_codec.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="process_decoded_line.hpp">
<ClInclude Include="copy_from_line_buffer.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="process_encoded_line.hpp">
<ClInclude Include="copy_to_line_buffer.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="quantization_lut.hpp">
Expand Down
34 changes: 4 additions & 30 deletions src/color_transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,9 @@ inline bool color_transformation_possible(const frame_info& frame) noexcept
}

// This file defines simple classes that define (lossless) color transforms.
// They are invoked in process_line.h to convert between decoded values and the internal line buffers.
// They are used to convert between decoded values and the internal line buffers.
// Color transforms work best for computer generated images, but are outside the official JPEG-LS specifications.

template<typename SampleType>
struct transform_none_impl
{
static_assert(std::is_integral_v<SampleType>, "Integral required.");

using sample_type = SampleType;

FORCE_INLINE triplet<SampleType> operator()(const int v1, const int v2, const int v3) const noexcept
{
return {v1, v2, v3};
}

FORCE_INLINE quad<SampleType> operator()(const int v1, const int v2, const int v3, const int v4) const noexcept
{
return {v1, v2, v3, v4};
}
};


template<typename SampleType>
struct transform_none final : transform_none_impl<SampleType>
{
static_assert(std::is_integral_v<SampleType>, "Integral required.");

using inverse = transform_none_impl<SampleType>;
};


template<typename SampleType>
struct transform_hp1 final
Expand All @@ -60,7 +33,7 @@ struct transform_hp1 final
{
FORCE_INLINE triplet<SampleType> operator()(const int v1, const int v2, const int v3) const noexcept
{
return {static_cast<SampleType>(v1 + v2 - range_ / 2), v2, static_cast<SampleType>(v3 + v2 - range_ / 2)};
return {static_cast<SampleType>(v1 + v2 - range_ / 2), static_cast<SampleType>(v2), static_cast<SampleType>(v3 + v2 - range_ / 2)};
}
};

Expand All @@ -78,7 +51,8 @@ struct transform_hp2 final

FORCE_INLINE triplet<SampleType> operator()(const int red, const int green, const int blue) const noexcept
{
return {static_cast<SampleType>(red - green + range_ / 2), green, static_cast<SampleType>(blue - ((red + green) >> 1) - range_ / 2)};
return {static_cast<SampleType>(red - green + range_ / 2), static_cast<SampleType>(green),
static_cast<SampleType>(blue - ((red + green) >> 1) - range_ / 2)};
}

struct inverse final
Expand Down
163 changes: 163 additions & 0 deletions src/copy_from_line_buffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright (c) Team CharLS.
// SPDX-License-Identifier: BSD-3-Clause

#pragma once

#include "color_transform.hpp"
#include "scan_codec.hpp"

#include <cstring>

// During decoding, CharLS process one line at a time.
// Conversions include color transforms, line interleaved vs sample interleaved, masking out unused bits,
// accounting for line padding etc.

namespace charls {

using copy_from_line_buffer_fn = void (*)(const void* source, void* destination, size_t pixel_count) noexcept;

template<typename SampleType>
class copy_from_line_buffer final
{
public:
[[nodiscard]]
static copy_from_line_buffer_fn get_copy_function(const interleave_mode interleave_mode, const int32_t component_count,
const color_transformation color_transformation) noexcept
{
switch (interleave_mode)
{
case interleave_mode::none:
return &copy_samples;

case interleave_mode::line:
if (component_count == 3)
{
switch (color_transformation)
{
case color_transformation::none:
return &copy_line_3_components;

case color_transformation::hp1:
return &copy_line_3_components_transform<transform_hp1<sample_type>>;

case color_transformation::hp2:
return &copy_line_3_components_transform<transform_hp2<sample_type>>;

case color_transformation::hp3:
return &copy_line_3_components_transform<transform_hp3<sample_type>>;
}
}

ASSERT(component_count == 4);
return &copy_line_4_components;

case interleave_mode::sample:
if (component_count == 3)
{
switch (color_transformation)
{
case color_transformation::none:
return &copy_pixels_3_components;

case color_transformation::hp1:
return &copy_pixels_3_components_transform<transform_hp1<sample_type>>;

case color_transformation::hp2:
return &copy_pixels_3_components_transform<transform_hp2<sample_type>>;

case color_transformation::hp3:
return &copy_pixels_3_components_transform<transform_hp3<sample_type>>;
}
}

ASSERT(component_count == 4);
return &copy_pixels_4_components;
}

unreachable();
}

private:
using sample_type = SampleType;

static void copy_samples(const void* source, void* destination, const size_t pixel_count) noexcept
{
memcpy(destination, source, pixel_count * sizeof(sample_type));
}

static void copy_line_3_components(const void* source, void* destination, const size_t pixel_count) noexcept
{
auto* s{static_cast<const sample_type*>(source)};
auto* d{static_cast<triplet<sample_type>*>(destination)};
const size_t pixel_stride{pixel_count_to_pixel_stride(pixel_count)};

for (size_t i{}; i != pixel_count; ++i)
{
d[i] = {s[i], s[i + pixel_stride], s[i + 2 * pixel_stride]};
}
}

template<typename Transform>
static void copy_line_3_components_transform(const void* source, void* destination, const size_t pixel_count) noexcept
{
copy_line_3_components_transform_impl(source, destination, pixel_count, typename Transform::inverse{});
}

template<typename Transform>
static void copy_line_3_components_transform_impl(const void* source, void* destination, const size_t pixel_count,
Transform transform) noexcept
{
auto* s{static_cast<const sample_type*>(source)};
auto* d{static_cast<triplet<sample_type>*>(destination)};
const size_t pixel_stride{pixel_count_to_pixel_stride(pixel_count)};

for (size_t i{}; i != pixel_count; ++i)
{
d[i] = transform(s[i], s[i + pixel_stride], s[i + 2 * pixel_stride]);
}
}

static void copy_line_4_components(const void* source, void* destination, const size_t pixel_count) noexcept
{
auto* s{static_cast<const sample_type*>(source)};
auto* d{static_cast<quad<sample_type>*>(destination)};
const size_t pixel_stride{pixel_count_to_pixel_stride(pixel_count)};

for (size_t i{}; i != pixel_count; ++i)
{
d[i] = {s[i], s[i + pixel_stride], s[i + 2 * pixel_stride], s[i + 3 * pixel_stride]};
}
}

static void copy_pixels_3_components(const void* source, void* destination, const size_t pixel_count) noexcept
{
memcpy(destination, source, pixel_count * sizeof(triplet<sample_type>));
}

template<typename Transform>
static void copy_pixels_3_components_transform(const void* source, void* destination, const size_t pixel_count) noexcept
{
copy_pixels_3_components_transform_impl(source, destination, pixel_count, typename Transform::inverse{});
}

template<typename Transform>
static void copy_pixels_3_components_transform_impl(const void* source, void* destination, const size_t pixel_count,
Transform transform) noexcept
{
auto* s{static_cast<const triplet<sample_type>*>(source)};
auto* d{static_cast<triplet<sample_type>*>(destination)};

for (size_t i{}; i != pixel_count; ++i)
{
const auto pixel{s[i]};
d[i] = transform(pixel.v1, pixel.v2, pixel.v3);
}
}

static void copy_pixels_4_components(const void* source, void* destination, const size_t pixel_count) noexcept
{
memcpy(destination, source, pixel_count * sizeof(quad<sample_type>));
}
};

} // namespace charls
Loading

0 comments on commit bbd2d34

Please sign in to comment.