mirror of
https://github.com/Xaymar/obs-StreamFX
synced 2024-11-10 22:05:06 +00:00
obs/gs/effect: Preprocess shaders to improve platform compatibility
Improves cross-platform compatibility of Shaders written for StreamFX through the use of preprocessing to make things a bit more compatible. While we don't perform any proper parsing, this will be able to prevent basic issues.
This commit is contained in:
parent
2ccbd76c02
commit
29bbe22bec
14 changed files with 223 additions and 108 deletions
|
@ -153,11 +153,11 @@ blur_instance::blur_instance(obs_data_t* settings, obs_source_t* self)
|
|||
|
||||
// Load Effects
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/mask.effect").string();
|
||||
auto file = streamfx::data_file_path("effects/mask.effect");
|
||||
try {
|
||||
_effect_mask = streamfx::obs::gs::effect::create(file);
|
||||
} catch (std::runtime_error& ex) {
|
||||
DLOG_ERROR("<filter-blur> Loading effect '%s' failed with error(s): %s", file.c_str(), ex.what());
|
||||
} catch (std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,38 +137,39 @@ color_grade_instance::color_grade_instance(obs_data_t* data, obs_source_t* self)
|
|||
|
||||
_lut_initialized(false), _lut_dirty(true), _lut_producer(), _lut_consumer()
|
||||
{
|
||||
// Load the color grading effect.
|
||||
auto path = streamfx::data_file_path("effects/color-grade.effect");
|
||||
if (!std::filesystem::exists(path)) {
|
||||
D_LOG_ERROR("Failed to locate effect file '%s'.", path.u8string().c_str());
|
||||
throw std::runtime_error("Failed to load color grade effect.");
|
||||
} else {
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
|
||||
// Load the color grading effect.
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/color-grade.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (std::exception& ex) {
|
||||
D_LOG_ERROR("Error loading '%s': %s", file.u8string().c_str(), ex.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize LUT work flow.
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(path.u8string());
|
||||
_lut_producer = std::make_shared<streamfx::gfx::lut::producer>();
|
||||
_lut_consumer = std::make_shared<streamfx::gfx::lut::consumer>();
|
||||
_lut_initialized = true;
|
||||
} catch (std::exception const& ex) {
|
||||
D_LOG_ERROR("Failed to load effect '%s': %s", path.u8string().c_str(), ex.what());
|
||||
D_LOG_WARNING("Failed to initialize LUT rendering, falling back to direct rendering.\n%s", ex.what());
|
||||
_lut_initialized = false;
|
||||
}
|
||||
|
||||
// Allocate render target for rendering.
|
||||
try {
|
||||
allocate_rendertarget(GS_RGBA);
|
||||
} catch (std::exception const& ex) {
|
||||
D_LOG_ERROR("Failed to acquire render target for rendering: %s", ex.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize LUT work flow.
|
||||
try {
|
||||
_lut_producer = std::make_shared<streamfx::gfx::lut::producer>();
|
||||
_lut_consumer = std::make_shared<streamfx::gfx::lut::consumer>();
|
||||
_lut_initialized = true;
|
||||
} catch (std::exception const& ex) {
|
||||
D_LOG_WARNING("Failed to initialize LUT rendering, falling back to direct rendering.\n%s", ex.what());
|
||||
_lut_initialized = false;
|
||||
}
|
||||
|
||||
// Allocate render target for rendering.
|
||||
try {
|
||||
allocate_rendertarget(GS_RGBA);
|
||||
} catch (std::exception const& ex) {
|
||||
D_LOG_ERROR("Failed to acquire render target for rendering: %s", ex.what());
|
||||
throw;
|
||||
}
|
||||
|
||||
update(data);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,19 @@ using namespace streamfx::filter::displacement;
|
|||
displacement_instance::displacement_instance(obs_data_t* data, obs_source_t* context)
|
||||
: obs::source_instance(data, context)
|
||||
{
|
||||
_effect = streamfx::obs::gs::effect::create(streamfx::data_file_path("effects/displace.effect").u8string());
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/displace.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (std::exception& ex) {
|
||||
D_LOG_ERROR("Error loading '%s': %s", file.u8string().c_str(), ex.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(data);
|
||||
}
|
||||
|
|
|
@ -77,13 +77,21 @@ dynamic_mask_instance::dynamic_mask_instance(obs_data_t* settings, obs_source_t*
|
|||
_filter_texture(), _have_input_texture(false), _input(), _input_capture(), _input_texture(),
|
||||
_have_final_texture(false), _final_rt(), _final_texture(), _channels(), _precalc()
|
||||
{
|
||||
_filter_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
_final_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(streamfx::data_file_path("effects/channel-mask.effect").u8string());
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Loading channel mask effect failed with error(s):\n%s", ex.what());
|
||||
_filter_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
_final_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/channel-mask.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (std::exception& ex) {
|
||||
D_LOG_ERROR("Error loading '%s': %s", file.u8string().c_str(), ex.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(settings);
|
||||
|
|
|
@ -145,12 +145,12 @@ sdf_effects_instance::sdf_effects_instance(obs_data_t* settings, obs_source_t* s
|
|||
{"effects/sdf/sdf-consumer.effect", _sdf_consumer_effect},
|
||||
};
|
||||
for (auto& kv : load_arr) {
|
||||
auto path = streamfx::data_file_path(kv.first).u8string();
|
||||
auto file = streamfx::data_file_path(kv.first);
|
||||
try {
|
||||
kv.second = streamfx::obs::gs::effect::create(path);
|
||||
} catch (const std::exception& ex) {
|
||||
D_LOG_ERROR("Failed to load effect '%s' (located at '%s') with error(s): %s", kv.first, path.c_str(),
|
||||
ex.what());
|
||||
kv.second = streamfx::obs::gs::effect::create(file);
|
||||
} catch (std::exception& ex) {
|
||||
D_LOG_ERROR("Error loading '%s': %s", file.u8string().c_str(), ex.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,42 +114,46 @@ transform_instance::transform_instance(obs_data_t* data, obs_source_t* context)
|
|||
_sampler(), _params(), _corners(), _cache_rendered(), _mipmap_enabled(), _source_rendered(), _source_size(),
|
||||
_update_mesh(true)
|
||||
{
|
||||
_cache_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
_source_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
_vertex_buffer = std::make_shared<streamfx::obs::gs::vertex_buffer>(uint32_t(4u), uint8_t(1u));
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/standard.effect");
|
||||
try {
|
||||
_standard_effect = streamfx::obs::gs::effect::create(file.generic_u8string());
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s' from disk: %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/transform.effect");
|
||||
try {
|
||||
_transform_effect = streamfx::obs::gs::effect::create(file.generic_u8string());
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s' from disk: %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
{
|
||||
_sampler.set_address_mode_u(GS_ADDRESS_CLAMP);
|
||||
_sampler.set_address_mode_v(GS_ADDRESS_CLAMP);
|
||||
_sampler.set_address_mode_w(GS_ADDRESS_CLAMP);
|
||||
_sampler.set_filter(GS_FILTER_LINEAR);
|
||||
_sampler.set_max_anisotropy(8);
|
||||
}
|
||||
auto gctx = obs::gs::context();
|
||||
|
||||
vec3_set(&_params.position, 0, 0, 0);
|
||||
vec3_set(&_params.rotation, 0, 0, 0);
|
||||
vec3_set(&_params.scale, 1, 1, 1);
|
||||
vec3_set(&_params.shear, 0, 0, 0);
|
||||
_cache_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
_source_rt = std::make_shared<streamfx::obs::gs::rendertarget>(GS_RGBA, GS_ZS_NONE);
|
||||
_vertex_buffer = std::make_shared<streamfx::obs::gs::vertex_buffer>(uint32_t(4u), uint8_t(1u));
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/standard.effect");
|
||||
try {
|
||||
_standard_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/transform.effect");
|
||||
try {
|
||||
_transform_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
{
|
||||
_sampler.set_address_mode_u(GS_ADDRESS_CLAMP);
|
||||
_sampler.set_address_mode_v(GS_ADDRESS_CLAMP);
|
||||
_sampler.set_address_mode_w(GS_ADDRESS_CLAMP);
|
||||
_sampler.set_filter(GS_FILTER_LINEAR);
|
||||
_sampler.set_max_anisotropy(8);
|
||||
}
|
||||
|
||||
vec2_set(&_corners.tl, 0, 0);
|
||||
vec2_set(&_corners.tr, 1, 0);
|
||||
vec2_set(&_corners.bl, 0, 1);
|
||||
vec2_set(&_corners.br, 1, 1);
|
||||
vec3_set(&_params.position, 0, 0, 0);
|
||||
vec3_set(&_params.rotation, 0, 0, 0);
|
||||
vec3_set(&_params.scale, 1, 1, 1);
|
||||
vec3_set(&_params.shear, 0, 0, 0);
|
||||
|
||||
vec2_set(&_corners.tl, 0, 0);
|
||||
vec2_set(&_corners.tr, 1, 0);
|
||||
vec2_set(&_corners.bl, 0, 1);
|
||||
vec2_set(&_corners.br, 1, 1);
|
||||
}
|
||||
|
||||
update(data);
|
||||
}
|
||||
|
|
|
@ -37,11 +37,13 @@
|
|||
streamfx::gfx::blur::box_linear_data::box_linear_data()
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
try {
|
||||
_effect =
|
||||
streamfx::obs::gs::effect::create(streamfx::data_file_path("effects/blur/box-linear.effect").u8string());
|
||||
} catch (...) {
|
||||
DLOG_ERROR("<gfx::blur::box_linear> Failed to load _effect.");
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/blur/box-linear.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,10 +37,13 @@
|
|||
streamfx::gfx::blur::box_data::box_data()
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(streamfx::data_file_path("effects/blur/box.effect").u8string());
|
||||
} catch (...) {
|
||||
DLOG_ERROR("<gfx::blur::box> Failed to load _effect.");
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/blur/box.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,11 +54,13 @@
|
|||
streamfx::gfx::blur::dual_filtering_data::dual_filtering_data()
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(
|
||||
streamfx::data_file_path("effects/blur/dual-filtering.effect").u8string());
|
||||
} catch (...) {
|
||||
DLOG_ERROR("<gfx::blur::box_linear> Failed to load _effect.");
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/blur/dual-filtering.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,9 +42,18 @@
|
|||
|
||||
streamfx::gfx::blur::gaussian_linear_data::gaussian_linear_data()
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
_effect =
|
||||
streamfx::obs::gs::effect::create(streamfx::data_file_path("effects/blur/gaussian-linear.effect").u8string());
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/blur/gaussian-linear.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Precalculate Kernels
|
||||
for (std::size_t kernel_size = 1; kernel_size <= ST_MAX_BLUR_SIZE; kernel_size++) {
|
||||
|
|
|
@ -46,8 +46,15 @@ streamfx::gfx::blur::gaussian_data::gaussian_data()
|
|||
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
_effect =
|
||||
streamfx::obs::gs::effect::create(streamfx::data_file_path("effects/blur/gaussian.effect").u8string());
|
||||
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/blur/gaussian.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#define ST_USE_PASCAL_TRIANGLE
|
||||
|
|
|
@ -19,28 +19,78 @@
|
|||
|
||||
#include "gs-effect.hpp"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include "obs/gs/gs-helper.hpp"
|
||||
#include "util/util-platform.hpp"
|
||||
|
||||
#define MAX_EFFECT_SIZE 32 * 1024 * 1024
|
||||
#define MAX_EFFECT_SIZE 32 * 1024 * 1024 // 32 MiB, big enough for everything.
|
||||
|
||||
static std::string load_file_as_code(std::filesystem::path file)
|
||||
static std::string load_file_as_code(std::filesystem::path shader_file)
|
||||
{
|
||||
uintmax_t size = std::filesystem::file_size(file);
|
||||
std::stringstream shader_stream;
|
||||
std::filesystem::path shader_path = std::filesystem::absolute(shader_file);
|
||||
std::filesystem::path shader_root = shader_path.parent_path();
|
||||
|
||||
// Ensure it meets size limits.
|
||||
uintmax_t size = std::filesystem::file_size(shader_path);
|
||||
if (size > MAX_EFFECT_SIZE) {
|
||||
throw std::runtime_error("File is too large to be loaded.");
|
||||
}
|
||||
|
||||
std::ifstream ifs(file, std::ios::binary);
|
||||
// Try to open as-is.
|
||||
std::ifstream ifs(shader_path, std::ios::in);
|
||||
if (!ifs.is_open() || ifs.bad()) {
|
||||
throw std::runtime_error("An unknown error occured trying to open the file.");
|
||||
throw std::runtime_error("Failed to open file.");
|
||||
}
|
||||
|
||||
std::vector<char> buf(size_t(size + 1), 0);
|
||||
ifs.read(buf.data(), static_cast<std::streamsize>(size));
|
||||
// Push Graphics API to shader.
|
||||
switch (gs_get_device_type()) {
|
||||
case GS_DEVICE_DIRECT3D_11:
|
||||
shader_stream << "#define GS_DEVICE_DIRECT3D_11" << std::endl;
|
||||
shader_stream << "#define GS_DEVICE_DIRECT3D" << std::endl;
|
||||
break;
|
||||
case GS_DEVICE_OPENGL:
|
||||
shader_stream << "#define GS_DEVICE_OPENGL" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
return std::string(buf.data(), buf.data() + size);
|
||||
// Pre-process the shader.
|
||||
std::string line;
|
||||
while (std::getline(ifs, line)) {
|
||||
std::string line_trimmed = line;
|
||||
|
||||
{ // Figure out the length of the trim.
|
||||
size_t trim_length = 0;
|
||||
for (size_t idx = 0, edx = line_trimmed.length(); idx < edx; idx++) {
|
||||
char ch = line_trimmed.at(idx);
|
||||
if ((ch != ' ') && (ch != '\t')) {
|
||||
trim_length = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trim_length > 0) {
|
||||
line_trimmed.erase(0, trim_length);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle '#include'
|
||||
if (line_trimmed.substr(0, 8) == "#include") {
|
||||
std::string include_str = line_trimmed.substr(10, line_trimmed.size() - 11); // '#include "'
|
||||
std::filesystem::path include_path = include_str;
|
||||
|
||||
if (!include_path.is_absolute()) {
|
||||
include_path = shader_root / include_str;
|
||||
}
|
||||
|
||||
line = load_file_as_code(include_path);
|
||||
}
|
||||
|
||||
shader_stream << line << std::endl;
|
||||
}
|
||||
|
||||
return shader_stream.str();
|
||||
}
|
||||
|
||||
streamfx::obs::gs::effect::effect(const std::string& code, const std::string& name)
|
||||
|
@ -58,7 +108,10 @@ streamfx::obs::gs::effect::effect(const std::string& code, const std::string& na
|
|||
reset(effect, [](gs_effect_t* ptr) { gs_effect_destroy(ptr); });
|
||||
}
|
||||
|
||||
streamfx::obs::gs::effect::effect(std::filesystem::path file) : effect(load_file_as_code(file), file.u8string()) {}
|
||||
streamfx::obs::gs::effect::effect(std::filesystem::path file)
|
||||
: effect(load_file_as_code(file),
|
||||
streamfx::util::platform::utf8_to_native(std::filesystem::absolute(file)).generic_u8string())
|
||||
{}
|
||||
|
||||
streamfx::obs::gs::effect::~effect()
|
||||
{
|
||||
|
|
|
@ -49,14 +49,19 @@ namespace streamfx::obs::gs {
|
|||
return get();
|
||||
}
|
||||
|
||||
static streamfx::obs::gs::effect create(const std::string& file)
|
||||
{
|
||||
return streamfx::obs::gs::effect(file);
|
||||
};
|
||||
|
||||
static streamfx::obs::gs::effect create(const std::string& code, const std::string& name)
|
||||
{
|
||||
return streamfx::obs::gs::effect(code, name);
|
||||
};
|
||||
|
||||
static streamfx::obs::gs::effect create(const std::string& file)
|
||||
{
|
||||
return streamfx::obs::gs::effect(std::filesystem::path(file));
|
||||
};
|
||||
|
||||
static streamfx::obs::gs::effect create(const std::filesystem::path& file)
|
||||
{
|
||||
return streamfx::obs::gs::effect(file);
|
||||
};
|
||||
};
|
||||
} // namespace streamfx::obs::gs
|
||||
|
|
|
@ -45,6 +45,8 @@ streamfx::obs::gs::mipmapper::~mipmapper()
|
|||
|
||||
streamfx::obs::gs::mipmapper::mipmapper()
|
||||
{
|
||||
auto gctx = streamfx::obs::gs::context();
|
||||
|
||||
_vb = std::make_unique<streamfx::obs::gs::vertex_buffer>(uint32_t(3u), uint8_t(1u));
|
||||
|
||||
{
|
||||
|
@ -71,7 +73,14 @@ streamfx::obs::gs::mipmapper::mipmapper()
|
|||
|
||||
_vb->update();
|
||||
|
||||
_effect = streamfx::obs::gs::effect::create(streamfx::data_file_path("effects/mipgen.effect").u8string());
|
||||
{
|
||||
auto file = streamfx::data_file_path("effects/mipgen.effect");
|
||||
try {
|
||||
_effect = streamfx::obs::gs::effect::create(file);
|
||||
} catch (const std::exception& ex) {
|
||||
DLOG_ERROR("Error loading '%s': %s", file.generic_u8string().c_str(), ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void streamfx::obs::gs::mipmapper::rebuild(std::shared_ptr<streamfx::obs::gs::texture> source,
|
||||
|
|
Loading…
Reference in a new issue