GPUShader: Add support for gpu_BaryCoord and fallback
This adds the possibility to use the `gpu_BaryCoord[NoPersp]` builtin to support barycentric coordinates without geometry shader. The `BuiltinBits::LAYER` builtin needs to be manually added to the `GPUShaderCreateInfo` in order to use this feature. Note: This is only available for shaders using `GPUShaderCreateInfo`. A geometry shader fallback is generated if the extension `AMD_shader_explicit_vertex_parameter` is not available. `NV_fragment_shader_barycentric` was not considered because it is not present inside the `glew.h` with use and seems to only be available with vulkan.
This commit is contained in:
@@ -249,6 +249,7 @@ static void detect_workarounds()
|
|||||||
GLContext::fixed_restart_index_support = false;
|
GLContext::fixed_restart_index_support = false;
|
||||||
GLContext::geometry_shader_invocations = false;
|
GLContext::geometry_shader_invocations = false;
|
||||||
GLContext::layered_rendering_support = false;
|
GLContext::layered_rendering_support = false;
|
||||||
|
GLContext::native_barycentric_support = false;
|
||||||
GLContext::multi_bind_support = false;
|
GLContext::multi_bind_support = false;
|
||||||
GLContext::multi_draw_indirect_support = false;
|
GLContext::multi_draw_indirect_support = false;
|
||||||
GLContext::shader_draw_parameters_support = false;
|
GLContext::shader_draw_parameters_support = false;
|
||||||
@@ -447,6 +448,7 @@ bool GLContext::explicit_location_support = false;
|
|||||||
bool GLContext::geometry_shader_invocations = false;
|
bool GLContext::geometry_shader_invocations = false;
|
||||||
bool GLContext::fixed_restart_index_support = false;
|
bool GLContext::fixed_restart_index_support = false;
|
||||||
bool GLContext::layered_rendering_support = false;
|
bool GLContext::layered_rendering_support = false;
|
||||||
|
bool GLContext::native_barycentric_support = false;
|
||||||
bool GLContext::multi_bind_support = false;
|
bool GLContext::multi_bind_support = false;
|
||||||
bool GLContext::multi_draw_indirect_support = false;
|
bool GLContext::multi_draw_indirect_support = false;
|
||||||
bool GLContext::shader_draw_parameters_support = false;
|
bool GLContext::shader_draw_parameters_support = false;
|
||||||
@@ -508,6 +510,7 @@ void GLBackend::capabilities_init()
|
|||||||
GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5;
|
GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5;
|
||||||
GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility;
|
GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility;
|
||||||
GLContext::layered_rendering_support = GLEW_AMD_vertex_shader_layer;
|
GLContext::layered_rendering_support = GLEW_AMD_vertex_shader_layer;
|
||||||
|
GLContext::native_barycentric_support = GLEW_AMD_shader_explicit_vertex_parameter;
|
||||||
GLContext::multi_bind_support = GLEW_ARB_multi_bind;
|
GLContext::multi_bind_support = GLEW_ARB_multi_bind;
|
||||||
GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect;
|
GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect;
|
||||||
GLContext::shader_draw_parameters_support = GLEW_ARB_shader_draw_parameters;
|
GLContext::shader_draw_parameters_support = GLEW_ARB_shader_draw_parameters;
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ class GLContext : public Context {
|
|||||||
static bool geometry_shader_invocations;
|
static bool geometry_shader_invocations;
|
||||||
static bool fixed_restart_index_support;
|
static bool fixed_restart_index_support;
|
||||||
static bool layered_rendering_support;
|
static bool layered_rendering_support;
|
||||||
|
static bool native_barycentric_support;
|
||||||
static bool multi_bind_support;
|
static bool multi_bind_support;
|
||||||
static bool multi_draw_indirect_support;
|
static bool multi_draw_indirect_support;
|
||||||
static bool shader_draw_parameters_support;
|
static bool shader_draw_parameters_support;
|
||||||
|
|||||||
@@ -424,9 +424,28 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string main_function_wrapper(std::string &pre_main, std::string &post_main)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
/* Prototype for the original main. */
|
||||||
|
ss << "\n";
|
||||||
|
ss << "void main_function_();\n";
|
||||||
|
/* Wrapper to the main function in order to inject code processing on globals. */
|
||||||
|
ss << "void main() {\n";
|
||||||
|
ss << pre_main;
|
||||||
|
ss << " main_function_();\n";
|
||||||
|
ss << post_main;
|
||||||
|
ss << "}\n";
|
||||||
|
/* Rename the original main. */
|
||||||
|
ss << "#define main main_function_\n";
|
||||||
|
ss << "\n";
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const
|
std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
std::string post_main = "";
|
||||||
|
|
||||||
ss << "\n/* Inputs. */\n";
|
ss << "\n/* Inputs. */\n";
|
||||||
for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
|
for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
|
||||||
@@ -442,13 +461,32 @@ std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) con
|
|||||||
if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) {
|
if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) {
|
||||||
ss << "out int gpu_Layer;\n";
|
ss << "out int gpu_Layer;\n";
|
||||||
}
|
}
|
||||||
|
if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) {
|
||||||
|
if (!GLContext::native_barycentric_support) {
|
||||||
|
/* Disabled or unsupported. */
|
||||||
|
}
|
||||||
|
else if (GLEW_AMD_shader_explicit_vertex_parameter) {
|
||||||
|
/* Need this for stable barycentric. */
|
||||||
|
ss << "flat out vec4 gpu_pos_flat;\n";
|
||||||
|
ss << "out vec4 gpu_pos;\n";
|
||||||
|
|
||||||
|
post_main += " gpu_pos = gpu_pos_flat = gl_Position;\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
ss << "\n";
|
ss << "\n";
|
||||||
|
|
||||||
|
if (post_main.empty() == false) {
|
||||||
|
std::string pre_main = "";
|
||||||
|
ss << main_function_wrapper(pre_main, post_main);
|
||||||
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const
|
std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
std::string pre_main = "";
|
||||||
|
|
||||||
ss << "\n/* Interfaces. */\n";
|
ss << "\n/* Interfaces. */\n";
|
||||||
const Vector<StageInterfaceInfo *> &in_interfaces = (info.geometry_source_.is_empty()) ?
|
const Vector<StageInterfaceInfo *> &in_interfaces = (info.geometry_source_.is_empty()) ?
|
||||||
info.vertex_out_interfaces_ :
|
info.vertex_out_interfaces_ :
|
||||||
@@ -456,6 +494,32 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
|
|||||||
for (const StageInterfaceInfo *iface : in_interfaces) {
|
for (const StageInterfaceInfo *iface : in_interfaces) {
|
||||||
print_interface(ss, "in", *iface);
|
print_interface(ss, "in", *iface);
|
||||||
}
|
}
|
||||||
|
if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) {
|
||||||
|
if (!GLContext::native_barycentric_support) {
|
||||||
|
ss << "smooth in vec3 gpu_BaryCoord;\n";
|
||||||
|
ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n";
|
||||||
|
}
|
||||||
|
else if (GLEW_AMD_shader_explicit_vertex_parameter) {
|
||||||
|
/* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry
|
||||||
|
* shader workaround if this extension/feature is detected. */
|
||||||
|
ss << "\n/* Stable Barycentric Coordinates. */\n";
|
||||||
|
ss << "flat in vec4 gpu_pos_flat;\n";
|
||||||
|
ss << "__explicitInterpAMD in vec4 gpu_pos;\n";
|
||||||
|
/* Globals. */
|
||||||
|
ss << "vec3 gpu_BaryCoord;\n";
|
||||||
|
ss << "vec3 gpu_BaryCoordNoPersp;\n";
|
||||||
|
ss << "\n";
|
||||||
|
ss << "vec2 stable_bary_(vec2 in_bary) {\n";
|
||||||
|
ss << " vec3 bary = vec3(in_bary, 1.0 - in_bary.x - in_bary.y);\n";
|
||||||
|
ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { return bary.zxy; }\n";
|
||||||
|
ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n";
|
||||||
|
ss << " return bary.xyz;\n";
|
||||||
|
ss << "}\n";
|
||||||
|
|
||||||
|
pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n";
|
||||||
|
pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
ss << "\n/* Outputs. */\n";
|
ss << "\n/* Outputs. */\n";
|
||||||
for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) {
|
for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) {
|
||||||
ss << "layout(location = " << output.index;
|
ss << "layout(location = " << output.index;
|
||||||
@@ -473,6 +537,11 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
|
|||||||
ss << "out " << to_string(output.type) << " " << output.name << ";\n";
|
ss << "out " << to_string(output.type) << " " << output.name << ";\n";
|
||||||
}
|
}
|
||||||
ss << "\n";
|
ss << "\n";
|
||||||
|
|
||||||
|
if (pre_main.empty() == false) {
|
||||||
|
std::string post_main = "";
|
||||||
|
ss << main_function_wrapper(pre_main, post_main);
|
||||||
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,7 +631,7 @@ std::string GLShader::workaround_geometry_shader_source_create(
|
|||||||
|
|
||||||
const bool do_layer_workaround = !GLContext::layered_rendering_support &&
|
const bool do_layer_workaround = !GLContext::layered_rendering_support &&
|
||||||
bool(info.builtins_ & BuiltinBits::LAYER);
|
bool(info.builtins_ & BuiltinBits::LAYER);
|
||||||
const bool do_barycentric_workaround = !GLContext::native_barycentrics_support &&
|
const bool do_barycentric_workaround = !GLContext::native_barycentric_support &&
|
||||||
bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD);
|
bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD);
|
||||||
|
|
||||||
shader::ShaderCreateInfo info_modified = info;
|
shader::ShaderCreateInfo info_modified = info;
|
||||||
@@ -578,6 +647,10 @@ std::string GLShader::workaround_geometry_shader_source_create(
|
|||||||
if (do_layer_workaround) {
|
if (do_layer_workaround) {
|
||||||
ss << "in int gpu_Layer[];\n";
|
ss << "in int gpu_Layer[];\n";
|
||||||
}
|
}
|
||||||
|
if (do_barycentric_workaround) {
|
||||||
|
ss << "smooth out vec3 gpu_BaryCoord;\n";
|
||||||
|
ss << "noperspective out vec3 gpu_BaryCoordNoPersp;\n";
|
||||||
|
}
|
||||||
ss << "\n";
|
ss << "\n";
|
||||||
|
|
||||||
ss << "void main()\n";
|
ss << "void main()\n";
|
||||||
@@ -592,6 +665,10 @@ std::string GLShader::workaround_geometry_shader_source_create(
|
|||||||
ss << " = " << iface->instance_name << "_in[" << i << "]." << inout.name << ";\n";
|
ss << " = " << iface->instance_name << "_in[" << i << "]." << inout.name << ";\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (do_barycentric_workaround) {
|
||||||
|
ss << " gpu_BaryCoordNoPersp = gpu_BaryCoord =";
|
||||||
|
ss << " vec3(" << int(i == 0) << ", " << int(i == 1) << ", " << int(i == 2) << ");\n";
|
||||||
|
}
|
||||||
ss << " gl_Position = gl_in[" << i << "].gl_Position;\n";
|
ss << " gl_Position = gl_in[" << i << "].gl_Position;\n";
|
||||||
ss << " EmitVertex();\n";
|
ss << " EmitVertex();\n";
|
||||||
}
|
}
|
||||||
@@ -602,7 +679,10 @@ std::string GLShader::workaround_geometry_shader_source_create(
|
|||||||
bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info)
|
bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info)
|
||||||
{
|
{
|
||||||
BuiltinBits builtins = info->builtins_;
|
BuiltinBits builtins = info->builtins_;
|
||||||
if (!GLContext::native_barycentrics_support && bool(builtins & BuiltinBits::BARYCENTRIC_COORD)) {
|
if (!GLContext::native_barycentric_support && bool(builtins & BuiltinBits::BARYCENTRIC_COORD)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!GLContext::layered_rendering_support && bool(builtins & BuiltinBits::LAYER)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -665,6 +745,9 @@ static char *glsl_patch_default_get()
|
|||||||
STR_CONCAT(patch, slen, "#extension GL_AMD_vertex_shader_layer: enable\n");
|
STR_CONCAT(patch, slen, "#extension GL_AMD_vertex_shader_layer: enable\n");
|
||||||
STR_CONCAT(patch, slen, "#define gpu_Layer gl_Layer\n");
|
STR_CONCAT(patch, slen, "#define gpu_Layer gl_Layer\n");
|
||||||
}
|
}
|
||||||
|
if (GLContext::native_barycentric_support) {
|
||||||
|
STR_CONCAT(patch, slen, "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* Fallbacks. */
|
/* Fallbacks. */
|
||||||
if (!GLContext::shader_draw_parameters_support) {
|
if (!GLContext::shader_draw_parameters_support) {
|
||||||
|
|||||||
Reference in New Issue
Block a user