From eba0a467d52401d3a75b16792894e7266a838d44 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Tue, 2 Feb 2021 22:25:06 +0100 Subject: [PATCH] gfx/lut: Add a simple but efficient LUT producer and consumer For simple image and video editing, LUTs (Look-Up Tables) are vastly superior to running the entire editing operation on each pixel - especially if all the processing can be done inside a single shader. Due to the post-processing requirements for our LUTs, we are limited to 8 bits per channel - though clever use of the unused Alpha channel may result in additional space. For our purposes however, this is definitely enough. --- CMakeLists.txt | 17 ++++ data/effects/lut-consumer.effect | 25 ++++++ data/effects/lut-producer.effect | 21 +++++ data/effects/lut.effect | 129 ++++++++++++++++++++++++++++ source/gfx/lut/gfx-lut-consumer.cpp | 79 +++++++++++++++++ source/gfx/lut/gfx-lut-consumer.hpp | 41 +++++++++ source/gfx/lut/gfx-lut-producer.cpp | 90 +++++++++++++++++++ source/gfx/lut/gfx-lut-producer.hpp | 39 +++++++++ source/gfx/lut/gfx-lut.cpp | 75 ++++++++++++++++ source/gfx/lut/gfx-lut.hpp | 62 +++++++++++++ 10 files changed, 578 insertions(+) create mode 100644 data/effects/lut-consumer.effect create mode 100644 data/effects/lut-producer.effect create mode 100644 data/effects/lut.effect create mode 100644 source/gfx/lut/gfx-lut-consumer.cpp create mode 100644 source/gfx/lut/gfx-lut-consumer.hpp create mode 100644 source/gfx/lut/gfx-lut-producer.cpp create mode 100644 source/gfx/lut/gfx-lut-producer.hpp create mode 100644 source/gfx/lut/gfx-lut.cpp create mode 100644 source/gfx/lut/gfx-lut.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ee4c28f5..ec7d34b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1315,6 +1315,23 @@ if(REQUIRE_PART_SHADER) ) endif() +# LUT +if(REQUIRE_LUT) + list(APPEND PROJECT_PRIVATE_SOURCE + "source/gfx/lut/gfx-lut.hpp" + "source/gfx/lut/gfx-lut.cpp" + "source/gfx/lut/gfx-lut-consumer.hpp" + "source/gfx/lut/gfx-lut-consumer.cpp" + "source/gfx/lut/gfx-lut-producer.hpp" + "source/gfx/lut/gfx-lut-producer.cpp" + ) + list(APPEND PROJECT_DATA + "data/effects/lut.effect" + "data/effects/lut-consumer.effect" + "data/effects/lut-producer.effect" + ) +endif() + # Windows if(D_PLATFORM_WINDOWS) list(APPEND PROJECT_PRIVATE_SOURCE diff --git a/data/effects/lut-consumer.effect b/data/effects/lut-consumer.effect new file mode 100644 index 00000000..f248f82c --- /dev/null +++ b/data/effects/lut-consumer.effect @@ -0,0 +1,25 @@ +#include "shared.effect" +#include "lut.effect" + +//------------------------------------------------------------------------------ +// Uniforms +//------------------------------------------------------------------------------ +uniform texture2d image; +uniform texture2d lut; +uniform int4 lut_params_0; // [size, grid_size, texture_size, 0] +uniform float4 lut_params_1; // [inverse_size, inverse_grid_size, inverse_texture_size, half_texel] + +//------------------------------------------------------------------------------ +// Functionality +//------------------------------------------------------------------------------ +float4 PSConsumeLUT(VertexData vtx) : TARGET { + float4 c = image.Sample(LinearClampSampler, vtx.uv); + return float4(sample_lut2(c.rgb, lut, lut_params_0, lut_params_1), c.a); +}; + +technique Draw { + pass { + vertex_shader = DefaultVertexShader(vtx); + pixel_shader = PSConsumeLUT(vtx); + } +} diff --git a/data/effects/lut-producer.effect b/data/effects/lut-producer.effect new file mode 100644 index 00000000..0adb59b8 --- /dev/null +++ b/data/effects/lut-producer.effect @@ -0,0 +1,21 @@ +#include "shared.effect" +#include "lut.effect" + +//------------------------------------------------------------------------------ +// Uniforms +//------------------------------------------------------------------------------ +uniform int4 lut_params_0; + +//------------------------------------------------------------------------------ +// Functionality +//------------------------------------------------------------------------------ +float4 PSProduceLUT(VertexData vtx) : TARGET { + return generate_lut2(vtx.uv, lut_params_0); +}; + +technique Draw { + pass { + vertex_shader = DefaultVertexShader(vtx); + pixel_shader = PSProduceLUT(vtx); + }; +}; diff --git a/data/effects/lut.effect b/data/effects/lut.effect new file mode 100644 index 00000000..c1b93cfd --- /dev/null +++ b/data/effects/lut.effect @@ -0,0 +1,129 @@ +sampler_state __LUTSampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +float4 generate_lut(uint bit_depth, float2 uv) { + uint size = pow(2, bit_depth); + uint z_size = pow(2, bit_depth / 2); + uint container_size = pow(2, bit_depth + (bit_depth / 2)); + + uint2 xy = uint2(floor(uv * container_size)); + uint2 rg = xy % size; + uint2 bb = xy / size; + + return float4( + rg.xy / float(size - 1), + ((bb.y * z_size) + bb.x) / float(size - 1), + 1. + ); +}; + +float4 generate_lut2(float2 uv, uint4 params0) { + uint size = params0.r; + uint z_size = params0.g; + uint container_size = params0.b; + + uint2 xy = uint2(floor(uv * container_size)); + uint2 rg = xy % size; + uint2 bb = xy / size; + + return float4( + rg.xy / float(size - 1), + ((bb.y * z_size) + bb.x) / float(size - 1), + 1. + ); +}; + +float3 sample_lut(float3 color, uint bit_depth, texture2D lut_texture) { + uint size = pow(2, bit_depth); + uint z_size = pow(2, bit_depth / 2); + uint container_size = pow(2, bit_depth + (bit_depth / 2)); + + float inverse_size = 1. / size; + float inverse_z_size = 1. / z_size; + float inverse_container_size = 1. / container_size; + float half_texel = inverse_container_size / 2.; // Linear sampling is weird. + + // Due to our LUT not actually being a cube but a plane pretending to be a cube, + // we have to do some conversion into the grid structure in order to be successful. + + // 1. Clamp everything to a reasonable range. + color = saturate(color); + + // 2. Rescale everything into 0..(size - 1) + color *= (size - 1); + + // 3. Convert red and green into initial grid cell UVs. + float2 xy_uv = color.xy * inverse_container_size; + + // 4. Figure out the high and low parts for interpolation. + uint z_lo = floor(color.z); + uint z_hi = z_lo + 1; + + // 5. Figure out the X location of the cell in the grid. + uint z_lo_x = z_lo % z_size; + uint z_hi_x = z_hi % z_size; + + // 6. Figure out the Y location of the cell in the grid. + uint z_lo_y = z_lo / z_size; + uint z_hi_y = z_hi / z_size; + + // 7. Convert the X and Y locations into UV coordinates. + float2 z_lo_uv = float2(z_lo_x, z_lo_y) * inverse_z_size; + float2 z_hi_uv = float2(z_hi_x, z_hi_y) * inverse_z_size; + + // 8. Sample both low and high points. + float3 c_lo = lut_texture.Sample(__LUTSampler, xy_uv + z_lo_uv + half_texel).rgb; + float3 c_hi = lut_texture.Sample(__LUTSampler, xy_uv + z_hi_uv + half_texel).rgb; + + // 9. Return an interpolated version based on the fraction of Z. + return lerp(c_lo, c_hi, frac(color.z)); +}; + +float3 sample_lut2(float3 color, texture2D lut_texture, int4 params0, float4 params1) { + uint size = params0.r; + uint z_size = params0.g; + uint container_size = params0.b; + + float inverse_size = params1.r; + float inverse_z_size = params1.g; + float inverse_container_size = params1.b; + float half_texel = params1.a; + + // Due to our LUT not actually being a cube but a plane pretending to be a cube, + // we have to do some conversion into the grid structure in order to be successful. + + // 1. Clamp everything to a reasonable range. + color = saturate(color); + + // 2. Rescale everything into 0..(size - 1) + color *= (size - 1); + + // 3. Convert red and green into initial grid cell UVs. + float2 xy_uv = color.xy * inverse_container_size; + + // 4. Figure out the high and low parts for interpolation. + uint z_lo = floor(color.z); + uint z_hi = z_lo + 1; + + // 5. Figure out the X location of the cell in the grid. + uint z_lo_x = z_lo % z_size; + uint z_hi_x = z_hi % z_size; + + // 6. Figure out the Y location of the cell in the grid. + uint z_lo_y = z_lo / z_size; + uint z_hi_y = z_hi / z_size; + + // 7. Convert the X and Y locations into UV coordinates. + float2 z_lo_uv = float2(z_lo_x, z_lo_y) * inverse_z_size; + float2 z_hi_uv = float2(z_hi_x, z_hi_y) * inverse_z_size; + + // 8. Sample both low and high points. + float3 c_lo = lut_texture.Sample(__LUTSampler, xy_uv + z_lo_uv + half_texel).rgb; + float3 c_hi = lut_texture.Sample(__LUTSampler, xy_uv + z_hi_uv + half_texel).rgb; + + // 9. Return an interpolated version based on the fraction of Z. + return lerp(c_lo, c_hi, frac(color.z)); +}; diff --git a/source/gfx/lut/gfx-lut-consumer.cpp b/source/gfx/lut/gfx-lut-consumer.cpp new file mode 100644 index 00000000..b930c216 --- /dev/null +++ b/source/gfx/lut/gfx-lut-consumer.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "gfx-lut-consumer.hpp" + +#include "obs/gs/gs-helper.hpp" + +gfx::lut::consumer::consumer() +{ + _data = gfx::lut::data::instance(); + if (!_data->consumer_effect()) + throw std::runtime_error("Unable to get LUT consumer effect."); +} + +gfx::lut::consumer::~consumer() {} + +std::shared_ptr gfx::lut::consumer::prepare(gfx::lut::color_depth depth, std::shared_ptr lut) +{ + auto gctx = gs::context(); + + auto effect = _data->consumer_effect(); + + int32_t idepth = static_cast(depth); + int32_t size = static_cast(pow(2l, idepth)); + int32_t grid_size = static_cast(pow(2l, (idepth / 2))); + int32_t container_size = static_cast(pow(2l, (idepth + (idepth / 2)))); + + if (gs::effect_parameter efp = effect->get_parameter("lut_params_0"); efp) { + efp.set_int4(size, grid_size, container_size, 0l); + } + + if (gs::effect_parameter efp = effect->get_parameter("lut_params_1"); efp) { + float inverse_size = 1.f / static_cast(size); + float inverse_z_size = 1.f / static_cast(grid_size); + float inverse_container_size = 1.f / static_cast(container_size); + float half_texel = inverse_container_size / 2.f; + efp.set_float4(inverse_size, inverse_z_size, inverse_container_size, half_texel); + } + + if (gs::effect_parameter efp = effect->get_parameter("lut"); efp) { + efp.set_texture(lut); + } + + return effect; +} + +void gfx::lut::consumer::consume(gfx::lut::color_depth depth, std::shared_ptr lut, + std::shared_ptr texture) +{ + auto gctx = gs::context(); + + auto effect = prepare(depth, lut); + + if (gs::effect_parameter efp = effect->get_parameter("image"); efp) { + efp.set_texture(texture->get_object()); + } + + // Draw a simple quad. + while (gs_effect_loop(effect->get_object(), "Draw")) { + gs_draw_sprite(nullptr, 0, 1, 1); + } +} diff --git a/source/gfx/lut/gfx-lut-consumer.hpp b/source/gfx/lut/gfx-lut-consumer.hpp new file mode 100644 index 00000000..a6b2d6c8 --- /dev/null +++ b/source/gfx/lut/gfx-lut-consumer.hpp @@ -0,0 +1,41 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once +#include + +#include "gfx-lut.hpp" +#include "obs/gs/gs-effect.hpp" +#include "obs/gs/gs-texture.hpp" + +namespace gfx::lut { + class consumer { + std::shared_ptr _data; + + public: + consumer(); + ~consumer(); + + std::shared_ptr prepare(gfx::lut::color_depth depth, std::shared_ptr lut); + + void consume(gfx::lut::color_depth depth, std::shared_ptr lut, + std::shared_ptr texture); + }; +} // namespace gfx::lut diff --git a/source/gfx/lut/gfx-lut-producer.cpp b/source/gfx/lut/gfx-lut-producer.cpp new file mode 100644 index 00000000..d220603c --- /dev/null +++ b/source/gfx/lut/gfx-lut-producer.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "gfx-lut-producer.hpp" + +#include "obs/gs/gs-helper.hpp" + +gs_color_format format_from_depth(gfx::lut::color_depth depth) +{ + switch (depth) { + case gfx::lut::color_depth::_2: + case gfx::lut::color_depth::_4: + case gfx::lut::color_depth::_6: + case gfx::lut::color_depth::_8: + return gs_color_format::GS_RGBA; + case gfx::lut::color_depth::_10: + return gs_color_format::GS_R10G10B10A2; + case gfx::lut::color_depth::_12: + case gfx::lut::color_depth::_14: + case gfx::lut::color_depth::_16: + return gs_color_format::GS_RGBA16; + } + return GS_RGBA32F; +} + +gfx::lut::producer::producer() +{ + _data = gfx::lut::data::instance(); + if (!_data->producer_effect()) + throw std::runtime_error("Unable to get LUT producer effect."); +} + +gfx::lut::producer::~producer() {} + +std::shared_ptr gfx::lut::producer::produce(gfx::lut::color_depth depth) +{ + auto gctx = gs::context(); + + if (!_rt || (_rt->get_color_format() != format_from_depth((depth)))) { + _rt = std::make_shared(format_from_depth(depth), GS_ZS_NONE); + } + + auto effect = _data->producer_effect(); + + int32_t idepth = static_cast(depth); + int32_t size = static_cast(pow(2l, idepth)); + int32_t grid_size = static_cast(pow(2l, (idepth / 2))); + int32_t container_size = static_cast(pow(2l, (idepth + (idepth / 2)))); + + { + auto op = _rt->render(static_cast(container_size), static_cast(container_size)); + + gs_blend_state_push(); + gs_enable_color(true, true, true, false); + gs_enable_blending(false); + gs_enable_stencil_test(false); + gs_enable_stencil_write(false); + gs_ortho(0, 1, 0, 1, 0, 1); + + if (gs::effect_parameter efp = effect->get_parameter("lut_params_0"); efp) { + efp.set_int4(size, grid_size, container_size, 0l); + } + + while (gs_effect_loop(effect->get_object(), "Draw")) { + streamfx::gs_draw_fullscreen_tri(); + } + + gs_enable_color(true, true, true, true); + gs_blend_state_pop(); + } + + return _rt->get_texture(); +} diff --git a/source/gfx/lut/gfx-lut-producer.hpp b/source/gfx/lut/gfx-lut-producer.hpp new file mode 100644 index 00000000..27b48796 --- /dev/null +++ b/source/gfx/lut/gfx-lut-producer.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once +#include + +#include "gfx-lut.hpp" +#include "obs/gs/gs-effect.hpp" +#include "obs/gs/gs-rendertarget.hpp" + +namespace gfx::lut { + class producer { + std::shared_ptr _data; + std::shared_ptr _rt; + + public: + producer(); + ~producer(); + + std::shared_ptr produce(gfx::lut::color_depth depth); + }; +} // namespace gfx::lut diff --git a/source/gfx/lut/gfx-lut.cpp b/source/gfx/lut/gfx-lut.cpp new file mode 100644 index 00000000..5a38c678 --- /dev/null +++ b/source/gfx/lut/gfx-lut.cpp @@ -0,0 +1,75 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "gfx-lut.hpp" + +#include + +#include "obs/gs/gs-helper.hpp" +#include "plugin.hpp" + +using namespace streamfx; + +#define LOCAL_PREFIX " " + +std::shared_ptr gfx::lut::data::instance() +{ + static std::weak_ptr _instance; + static std::mutex _mutex; + + std::lock_guard lock(_mutex); + + auto reference = _instance.lock(); + if (!reference) { + reference = std::shared_ptr(new gfx::lut::data()); + _instance = reference; + } + return reference; +} + +gfx::lut::data::data() : _producer_effect(), _consumer_effect() +{ + auto gctx = gs::context(); + + std::filesystem::path lut_producer_path = streamfx::data_file_path("effects/lut-producer.effect"); + if (std::filesystem::exists(lut_producer_path)) { + try { + _producer_effect = std::make_shared(lut_producer_path); + } catch (std::exception const& ex) { + DLOG_ERROR(LOCAL_PREFIX "Loading LUT Producer effect failed: %s", ex.what()); + } + } + + std::filesystem::path lut_consumer_path = streamfx::data_file_path("effects/lut-consumer.effect"); + if (std::filesystem::exists(lut_consumer_path)) { + try { + _consumer_effect = std::make_shared(lut_consumer_path); + } catch (std::exception const& ex) { + DLOG_ERROR(LOCAL_PREFIX "Loading LUT Consumer effect failed: %s", ex.what()); + } + } +} + +gfx::lut::data::~data() +{ + auto gctx = gs::context(); + _producer_effect.reset(); + _consumer_effect.reset(); +} diff --git a/source/gfx/lut/gfx-lut.hpp b/source/gfx/lut/gfx-lut.hpp new file mode 100644 index 00000000..e40705d3 --- /dev/null +++ b/source/gfx/lut/gfx-lut.hpp @@ -0,0 +1,62 @@ +// Copyright (c) 2021 Michael Fabian Dirks +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once +#include + +#include "obs/gs/gs-effect.hpp" + +namespace gfx::lut { + class data { + std::shared_ptr _producer_effect; + std::shared_ptr _consumer_effect; + + public: + static std::shared_ptr instance(); + + private: + data(); + + public: + ~data(); + + inline std::shared_ptr producer_effect() + { + return _producer_effect; + }; + + inline std::shared_ptr consumer_effect() + { + return _consumer_effect; + }; + }; + + enum class color_depth { + Invalid = 0, + _2 = 2, + _4 = 4, + _6 = 6, + _8 = 8, + _10 = 10, + _12 = 12, + _14 = 14, + _16 = 16, + }; +} // namespace gfx::lut