|
@@ -38,6 +38,7 @@ namespace graphics
|
|
|
|
|
|
namespace glsl
|
|
|
{
|
|
|
+
|
|
|
static const char global_syntax[] = R"(
|
|
|
#if !defined(GL_ES) && __VERSION__ < 140
|
|
|
#define lowp
|
|
@@ -275,6 +276,16 @@ void main() {
|
|
|
}
|
|
|
)";
|
|
|
|
|
|
+static const char vertex_main_raw[] = R"(
|
|
|
+void vertexmain();
|
|
|
+
|
|
|
+void main() {
|
|
|
+ love_initializeBuiltinUniforms();
|
|
|
+ setPointSize();
|
|
|
+ vertexmain();
|
|
|
+}
|
|
|
+)";
|
|
|
+
|
|
|
static const char pixel_header[] = R"(
|
|
|
#ifdef GL_ES
|
|
|
precision mediump float;
|
|
@@ -284,29 +295,10 @@ static const char pixel_header[] = R"(
|
|
|
|
|
|
#if __VERSION__ >= 130
|
|
|
#define varying in
|
|
|
- // Some drivers seem to make the pixel shader do more work when multiple
|
|
|
- // pixel shader outputs are defined, even when only one is actually used.
|
|
|
- // TODO: We should use reflection or something instead of this, to determine
|
|
|
- // how many outputs are actually used in the shader code.
|
|
|
- #ifdef LOVE_MULTI_RENDER_TARGETS
|
|
|
- layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets];
|
|
|
- #define love_PixelColor love_RenderTargets[0]
|
|
|
- #else
|
|
|
- layout(location = 0) out vec4 love_PixelColor;
|
|
|
- #endif
|
|
|
-#else
|
|
|
- #ifdef LOVE_MULTI_RENDER_TARGETS
|
|
|
- #define love_RenderTargets gl_FragData
|
|
|
- #endif
|
|
|
- #define love_PixelColor gl_FragColor
|
|
|
#endif
|
|
|
|
|
|
// Legacy
|
|
|
#define love_MaxCanvases love_MaxRenderTargets
|
|
|
-#define love_Canvases love_RenderTargets
|
|
|
-#ifdef LOVE_MULTI_RENDER_TARGETS
|
|
|
-#define LOVE_MULTI_CANVASES 1
|
|
|
-#endif
|
|
|
|
|
|
// See Shader::updateScreenParams in Shader.cpp.
|
|
|
#define love_PixelCoord (vec2(gl_FragCoord.x, (gl_FragCoord.y * love_ScreenSize.z) + love_ScreenSize.w))
|
|
@@ -335,6 +327,12 @@ vec4 VideoTexel(vec2 texcoords) {
|
|
|
)";
|
|
|
|
|
|
static const char pixel_main[] = R"(
|
|
|
+#if __VERSION__ >= 130
|
|
|
+ layout(location = 0) out vec4 love_PixelColor;
|
|
|
+#else
|
|
|
+ #define love_PixelColor gl_FragColor
|
|
|
+#endif
|
|
|
+
|
|
|
uniform sampler2D MainTex;
|
|
|
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
|
|
|
varying mediump vec4 VaryingColor;
|
|
@@ -348,6 +346,30 @@ void main() {
|
|
|
)";
|
|
|
|
|
|
static const char pixel_main_custom[] = R"(
|
|
|
+#if __VERSION__ >= 130
|
|
|
+ // Some drivers seem to make the pixel shader do more work when multiple
|
|
|
+ // pixel shader outputs are defined, even when only one is actually used.
|
|
|
+ // TODO: We should use reflection or something instead of this, to determine
|
|
|
+ // how many outputs are actually used in the shader code.
|
|
|
+ #ifdef LOVE_MULTI_RENDER_TARGETS
|
|
|
+ layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets];
|
|
|
+ #define love_PixelColor love_RenderTargets[0]
|
|
|
+ #else
|
|
|
+ layout(location = 0) out vec4 love_PixelColor;
|
|
|
+ #endif
|
|
|
+#else
|
|
|
+ #ifdef LOVE_MULTI_RENDER_TARGETS
|
|
|
+ #define love_RenderTargets gl_FragData
|
|
|
+ #endif
|
|
|
+ #define love_PixelColor gl_FragColor
|
|
|
+#endif
|
|
|
+
|
|
|
+// Legacy
|
|
|
+#define love_Canvases love_RenderTargets
|
|
|
+#ifdef LOVE_MULTI_RENDER_TARGETS
|
|
|
+#define LOVE_MULTI_CANVASES 1
|
|
|
+#endif
|
|
|
+
|
|
|
varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
|
|
|
varying mediump vec4 VaryingColor;
|
|
|
|
|
@@ -359,6 +381,15 @@ void main() {
|
|
|
}
|
|
|
)";
|
|
|
|
|
|
+static const char pixel_main_raw[] = R"(
|
|
|
+void pixelmain();
|
|
|
+
|
|
|
+void main() {
|
|
|
+ love_initializeBuiltinUniforms();
|
|
|
+ pixelmain();
|
|
|
+}
|
|
|
+)";
|
|
|
+
|
|
|
struct StageInfo
|
|
|
{
|
|
|
const char *name;
|
|
@@ -366,12 +397,13 @@ struct StageInfo
|
|
|
const char *functions;
|
|
|
const char *main;
|
|
|
const char *main_custom;
|
|
|
+ const char *main_raw;
|
|
|
};
|
|
|
|
|
|
static const StageInfo stageInfo[] =
|
|
|
{
|
|
|
- { "VERTEX", vertex_header, vertex_functions, vertex_main, vertex_main },
|
|
|
- { "PIXEL", pixel_header, pixel_functions, pixel_main, pixel_main_custom },
|
|
|
+ { "VERTEX", vertex_header, vertex_functions, vertex_main, vertex_main, vertex_main_raw },
|
|
|
+ { "PIXEL", pixel_header, pixel_functions, pixel_main, pixel_main_custom, pixel_main_raw },
|
|
|
};
|
|
|
|
|
|
static_assert((sizeof(stageInfo) / sizeof(StageInfo)) == ShaderStage::STAGE_MAX_ENUM, "Stages array size must match ShaderStage enum.");
|
|
@@ -400,30 +432,38 @@ static Shader::Language getTargetLanguage(const std::string &src)
|
|
|
return lang;
|
|
|
}
|
|
|
|
|
|
-static bool isVertexCode(const std::string &src)
|
|
|
+static Shader::EntryPoint getVertexEntryPoint(const std::string &src)
|
|
|
{
|
|
|
- std::regex r("vec4\\s+position\\s*\\(");
|
|
|
std::smatch m;
|
|
|
- return std::regex_search(src, m, r);
|
|
|
+
|
|
|
+ if (std::regex_search(src, m, std::regex("void\\s+vertexmain\\s*\\(")))
|
|
|
+ return Shader::ENTRYPOINT_RAW;
|
|
|
+
|
|
|
+ if (std::regex_search(src, m, std::regex("vec4\\s+position\\s*\\(")))
|
|
|
+ return Shader::ENTRYPOINT_HIGHLEVEL;
|
|
|
+
|
|
|
+ return Shader::ENTRYPOINT_NONE;
|
|
|
}
|
|
|
|
|
|
-static bool isPixelCode(const std::string &src, bool &custompixel, bool &mrt)
|
|
|
+static Shader::EntryPoint getPixelEntryPoint(const std::string &src, bool &mrt)
|
|
|
{
|
|
|
- custompixel = false;
|
|
|
mrt = false;
|
|
|
std::smatch m;
|
|
|
+
|
|
|
+ if (std::regex_search(src, m, std::regex("void\\s+pixelmain\\s*\\(")))
|
|
|
+ return Shader::ENTRYPOINT_RAW;
|
|
|
+
|
|
|
if (std::regex_search(src, m, std::regex("vec4\\s+effect\\s*\\(")))
|
|
|
- return true;
|
|
|
+ return Shader::ENTRYPOINT_HIGHLEVEL;
|
|
|
|
|
|
if (std::regex_search(src, m, std::regex("void\\s+effect\\s*\\(")))
|
|
|
{
|
|
|
- custompixel = true;
|
|
|
if (src.find("love_RenderTargets") != std::string::npos || src.find("love_Canvases") != std::string::npos)
|
|
|
mrt = true;
|
|
|
- return true;
|
|
|
+ return Shader::ENTRYPOINT_CUSTOM;
|
|
|
}
|
|
|
|
|
|
- return false;
|
|
|
+ return Shader::ENTRYPOINT_NONE;
|
|
|
}
|
|
|
|
|
|
} // glsl
|
|
@@ -439,8 +479,8 @@ Shader::SourceInfo Shader::getSourceInfo(const std::string &src)
|
|
|
{
|
|
|
SourceInfo info = {};
|
|
|
info.language = glsl::getTargetLanguage(src);
|
|
|
- info.isStage[ShaderStage::STAGE_VERTEX] = glsl::isVertexCode(src);
|
|
|
- info.isStage[ShaderStage::STAGE_PIXEL] = glsl::isPixelCode(src, info.customPixelFunction, info.usesMRT);
|
|
|
+ info.stages[ShaderStage::STAGE_VERTEX] = glsl::getVertexEntryPoint(src);
|
|
|
+ info.stages[ShaderStage::STAGE_PIXEL] = glsl::getPixelEntryPoint(src, info.usesMRT);
|
|
|
return info;
|
|
|
}
|
|
|
|
|
@@ -449,6 +489,12 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStage::StageType
|
|
|
if (info.language == Shader::LANGUAGE_MAX_ENUM)
|
|
|
throw love::Exception("Invalid shader language");
|
|
|
|
|
|
+ if (info.stages[stage] == ENTRYPOINT_NONE)
|
|
|
+ throw love::Exception("Cannot find entry point for shader stage.");
|
|
|
+
|
|
|
+ if (info.stages[stage] == ENTRYPOINT_RAW && info.language == LANGUAGE_GLSL1)
|
|
|
+ throw love::Exception("Shaders using a raw entry point must use GLSL 3 or greater.");
|
|
|
+
|
|
|
const auto &features = gfx->getCapabilities().features;
|
|
|
|
|
|
if (info.language == LANGUAGE_GLSL3 && !features[Graphics::FEATURE_GLSL3])
|
|
@@ -481,7 +527,15 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStage::StageType
|
|
|
ss << glsl::global_uniforms;
|
|
|
ss << glsl::global_functions;
|
|
|
ss << stageinfo.functions;
|
|
|
- ss << (info.customPixelFunction ? stageinfo.main_custom : stageinfo.main);
|
|
|
+
|
|
|
+ if (info.stages[stage] == ENTRYPOINT_HIGHLEVEL)
|
|
|
+ ss << stageinfo.main;
|
|
|
+ else if (info.stages[stage] == ENTRYPOINT_CUSTOM)
|
|
|
+ ss << stageinfo.main_custom;
|
|
|
+ else if (info.stages[stage] == ENTRYPOINT_RAW)
|
|
|
+ ss << stageinfo.main_raw;
|
|
|
+ else
|
|
|
+ throw love::Exception("Unknown shader entry point %d", info.stages[stage]);
|
|
|
ss << ((!gles && (lang == Shader::LANGUAGE_GLSL1 || glsl1on3)) ? "#line 0\n" : "#line 1\n");
|
|
|
ss << code;
|
|
|
|