mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-12-29 11:01:23 +00:00
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.
This commit is contained in:
parent
73f9257633
commit
eba0a467d5
10 changed files with 578 additions and 0 deletions
|
@ -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
|
||||
|
|
25
data/effects/lut-consumer.effect
Normal file
25
data/effects/lut-consumer.effect
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
21
data/effects/lut-producer.effect
Normal file
21
data/effects/lut-producer.effect
Normal file
|
@ -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);
|
||||
};
|
||||
};
|
129
data/effects/lut.effect
Normal file
129
data/effects/lut.effect
Normal file
|
@ -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));
|
||||
};
|
79
source/gfx/lut/gfx-lut-consumer.cpp
Normal file
79
source/gfx/lut/gfx-lut-consumer.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) 2021 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// 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<gs::effect> gfx::lut::consumer::prepare(gfx::lut::color_depth depth, std::shared_ptr<gs::texture> lut)
|
||||
{
|
||||
auto gctx = gs::context();
|
||||
|
||||
auto effect = _data->consumer_effect();
|
||||
|
||||
int32_t idepth = static_cast<int32_t>(depth);
|
||||
int32_t size = static_cast<int32_t>(pow(2l, idepth));
|
||||
int32_t grid_size = static_cast<int32_t>(pow(2l, (idepth / 2)));
|
||||
int32_t container_size = static_cast<int32_t>(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<float>(size);
|
||||
float inverse_z_size = 1.f / static_cast<float>(grid_size);
|
||||
float inverse_container_size = 1.f / static_cast<float>(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<gs::texture> lut,
|
||||
std::shared_ptr<gs::texture> 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);
|
||||
}
|
||||
}
|
41
source/gfx/lut/gfx-lut-consumer.hpp
Normal file
41
source/gfx/lut/gfx-lut-consumer.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2021 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// 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 <memory>
|
||||
|
||||
#include "gfx-lut.hpp"
|
||||
#include "obs/gs/gs-effect.hpp"
|
||||
#include "obs/gs/gs-texture.hpp"
|
||||
|
||||
namespace gfx::lut {
|
||||
class consumer {
|
||||
std::shared_ptr<gfx::lut::data> _data;
|
||||
|
||||
public:
|
||||
consumer();
|
||||
~consumer();
|
||||
|
||||
std::shared_ptr<gs::effect> prepare(gfx::lut::color_depth depth, std::shared_ptr<gs::texture> lut);
|
||||
|
||||
void consume(gfx::lut::color_depth depth, std::shared_ptr<gs::texture> lut,
|
||||
std::shared_ptr<gs::texture> texture);
|
||||
};
|
||||
} // namespace gfx::lut
|
90
source/gfx/lut/gfx-lut-producer.cpp
Normal file
90
source/gfx/lut/gfx-lut-producer.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2021 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// 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<gs::texture> 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<gs::rendertarget>(format_from_depth(depth), GS_ZS_NONE);
|
||||
}
|
||||
|
||||
auto effect = _data->producer_effect();
|
||||
|
||||
int32_t idepth = static_cast<int32_t>(depth);
|
||||
int32_t size = static_cast<int32_t>(pow(2l, idepth));
|
||||
int32_t grid_size = static_cast<int32_t>(pow(2l, (idepth / 2)));
|
||||
int32_t container_size = static_cast<int32_t>(pow(2l, (idepth + (idepth / 2))));
|
||||
|
||||
{
|
||||
auto op = _rt->render(static_cast<uint32_t>(container_size), static_cast<uint32_t>(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();
|
||||
}
|
39
source/gfx/lut/gfx-lut-producer.hpp
Normal file
39
source/gfx/lut/gfx-lut-producer.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2021 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// 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 <memory>
|
||||
|
||||
#include "gfx-lut.hpp"
|
||||
#include "obs/gs/gs-effect.hpp"
|
||||
#include "obs/gs/gs-rendertarget.hpp"
|
||||
|
||||
namespace gfx::lut {
|
||||
class producer {
|
||||
std::shared_ptr<gfx::lut::data> _data;
|
||||
std::shared_ptr<gs::rendertarget> _rt;
|
||||
|
||||
public:
|
||||
producer();
|
||||
~producer();
|
||||
|
||||
std::shared_ptr<gs::texture> produce(gfx::lut::color_depth depth);
|
||||
};
|
||||
} // namespace gfx::lut
|
75
source/gfx/lut/gfx-lut.cpp
Normal file
75
source/gfx/lut/gfx-lut.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2021 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// 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 <mutex>
|
||||
|
||||
#include "obs/gs/gs-helper.hpp"
|
||||
#include "plugin.hpp"
|
||||
|
||||
using namespace streamfx;
|
||||
|
||||
#define LOCAL_PREFIX "<gfx::lut::data> "
|
||||
|
||||
std::shared_ptr<gfx::lut::data> gfx::lut::data::instance()
|
||||
{
|
||||
static std::weak_ptr<gfx::lut::data> _instance;
|
||||
static std::mutex _mutex;
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
|
||||
auto reference = _instance.lock();
|
||||
if (!reference) {
|
||||
reference = std::shared_ptr<gfx::lut::data>(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<gs::effect>(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<gs::effect>(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();
|
||||
}
|
62
source/gfx/lut/gfx-lut.hpp
Normal file
62
source/gfx/lut/gfx-lut.hpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2021 Michael Fabian Dirks <info@xaymar.com>
|
||||
//
|
||||
// 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 <memory>
|
||||
|
||||
#include "obs/gs/gs-effect.hpp"
|
||||
|
||||
namespace gfx::lut {
|
||||
class data {
|
||||
std::shared_ptr<gs::effect> _producer_effect;
|
||||
std::shared_ptr<gs::effect> _consumer_effect;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<data> instance();
|
||||
|
||||
private:
|
||||
data();
|
||||
|
||||
public:
|
||||
~data();
|
||||
|
||||
inline std::shared_ptr<gs::effect> producer_effect()
|
||||
{
|
||||
return _producer_effect;
|
||||
};
|
||||
|
||||
inline std::shared_ptr<gs::effect> 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
|
Loading…
Reference in a new issue