From a3fdca7997ff3dc331c2d30ea75f820522295326 Mon Sep 17 00:00:00 2001 From: Eliza Velasquez Date: Mon, 30 Oct 2023 16:35:34 -0700 Subject: [PATCH] Fix basic post processing on ES2 First, this commit introduces some very simple bugfixes regarding ES2 compatibility related to postprocessing. Second, this commit adds support for creating textures specified as R8, SRGB8, and SRGB8_A8 in ES2. R8 is trivial: just use GL_LUMINANCE instead. The sRGB formats, however, are maybe a bit more controversial. As implemented, they instead just use the equivalent non-sRGB formats. This is of course technically incorrect. There are a few approaches to how to add sRGB compatibility for ES2 that I can think of. 1. Do a bunch of complex shader nonsense in matc. Maybe even traversing the AST and ensuring any texture lookup of a texture flagged as sRGB uses some compatibility function. This would require static analysis to track if samplers are reassigned to another variable, for example. This of course also breaks down if you don't know at compile time if the shader will receive an RGB or an sRGB sampler, or if the shader should be able to support both RGB or sRGB samplers. Really only worth mentioning here for the sake of completion. 2. You could also generate simple compatibility functions to look up each sampler, which would only apply to FL0 materials. First, we would have to extend the material format to be able to explicitly "color" a sampler as sRGB or not, like: ``` parameters : [ { type : sampler2d, name : albedo, precision : medium, colorSpace : srgb, }, { type : sampler2d, name : normal, precision : medium, colorSpace : linear, } ], ``` Then, the following GLSL code would be generated. ```glsl \#if __VERSION__ == 100 vec4 texture_albedo(vec2 position) { return sRGBtoLinear(texture2D(materialParams_albedo, position)); } vec4 texture_normal(vec2 position) { return texture2D(materialParams_albedo, position); } \#else vec4 texture_albedo(vec2 position) { return texture(materialParams_albedo, position); } vec4 texture_normal(vec2 normal) { return texture(materialParams_normal, position); } \#endif ``` Finally, at runtime, if a sampler is "colored" one way or the other, we would verify that only the appropriate kinds of samplers are bound. I'm actually very partial to this solution. Since sRGB compatibility is only a concern on ES2, we can generate this code only for FL0 shaders, which already require GLSL shader authors to care about ESSL 1.0 compatibility by calling the appropriate `textureXX` functions. Additionally, it provides a layer of high-level validation that texture lookups are correct, even if a real ES2 context is not available on the device being tested. 3. Leave it entirely up to the client. (What this commit does.) This leaves client code ripe for making mistakes, but luckily, we can go back and do solution 2 whenever. If specifying a color space for a sampler remains optional, then if this feature is retrofitted in the future, client code will continue to compile. --- NEW_RELEASE_NOTES.md | 1 + filament/backend/src/opengl/GLUtils.h | 21 +++++++++++--------- filament/backend/src/opengl/OpenGLDriver.cpp | 20 ++++++++++++++++--- libs/filamat/src/shaders/CodeGenerator.cpp | 2 ++ shaders/src/post_process_inputs.vs | 2 +- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 8c601cd27a..977e98846d 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -15,3 +15,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). - matc: Add support for post-process materials in feature level 0 - engine: Add `Material::getFeatureLevel()` - engine: Add missing `Material::getReflectionMode()` method in Java +- engine: Support basic usage of post-processing materials on feature level 0 diff --git a/filament/backend/src/opengl/GLUtils.h b/filament/backend/src/opengl/GLUtils.h index 0c7bca140e..dc9df7871a 100644 --- a/filament/backend/src/opengl/GLUtils.h +++ b/filament/backend/src/opengl/GLUtils.h @@ -373,16 +373,19 @@ constexpr inline GLenum getCullingMode(CullingMode mode) noexcept { constexpr inline std::pair textureFormatToFormatAndType( TextureFormat format) noexcept { switch (format) { - case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE }; - case TextureFormat::RGBA8: return { GL_RGBA, GL_UNSIGNED_BYTE }; - case TextureFormat::RGB565: return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }; - case TextureFormat::RGB5_A1: return { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }; - case TextureFormat::RGBA4: return { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }; - case TextureFormat::DEPTH16: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }; - case TextureFormat::DEPTH24: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; + case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE }; + case TextureFormat::RGB8: return { GL_RGB, GL_UNSIGNED_BYTE }; + case TextureFormat::SRGB8: return { GL_RGB, GL_UNSIGNED_BYTE }; + case TextureFormat::RGBA8: return { GL_RGBA, GL_UNSIGNED_BYTE }; + case TextureFormat::SRGB8_A8: return { GL_RGBA, GL_UNSIGNED_BYTE }; + case TextureFormat::RGB565: return { GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }; + case TextureFormat::RGB5_A1: return { GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }; + case TextureFormat::RGBA4: return { GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4 }; + case TextureFormat::DEPTH16: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }; + case TextureFormat::DEPTH24: return { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }; case TextureFormat::DEPTH24_STENCIL8: - return { GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8 }; - default: return { GL_NONE, GL_NONE }; + return { GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8 }; + default: return { GL_NONE, GL_NONE }; } } diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index bbfb76a26a..9e9f1c8ace 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -1290,7 +1290,9 @@ void OpenGLDriver::createRenderTargetR(Handle rth, checkDimensions(rt->gl.color[i], color[i].level); } } - glDrawBuffers((GLsizei)maxDrawBuffers, bufs); + if (UTILS_LIKELY(!getContext().isES2())) { + glDrawBuffers((GLsizei)maxDrawBuffers, bufs); + } CHECK_GL_ERROR(utils::slog.e) } #endif @@ -1782,6 +1784,10 @@ bool OpenGLDriver::isRenderTargetFormatSupported(TextureFormat format) { // support more formats, but it requires querying GL_INTERNALFORMAT_SUPPORTED which is not // available in OpenGL ES. auto& gl = mContext; + if (UTILS_UNLIKELY(gl.isES2())) { + auto [es2format, type] = textureFormatToFormatAndType(format); + return es2format != GL_NONE && type != GL_NONE; + } switch (format) { // Core formats. case TextureFormat::R8: @@ -2276,8 +2282,16 @@ void OpenGLDriver::setTextureData(GLTexture* t, uint32_t level, return; } - GLenum const glFormat = getFormat(p.format); - GLenum const glType = getType(p.type); + GLenum glFormat; + GLenum glType; + if (mContext.isES2()) { + auto formatAndType = textureFormatToFormatAndType(t->format); + glFormat = formatAndType.first; + glType = formatAndType.second; + } else { + glFormat = getFormat(p.format); + glType = getType(p.type); + } #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 if (!gl.isES2()) { diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index 214ca50f3f..e1dbd80ba2 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -164,11 +164,13 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) { if (stage == ShaderStage::VERTEX) { generateDefine(out, "VARYING", "out"); + generateDefine(out, "ATTRIBUTE", "in"); } else if (stage == ShaderStage::FRAGMENT) { generateDefine(out, "VARYING", "in"); } } else { generateDefine(out, "VARYING", "varying"); + generateDefine(out, "ATTRIBUTE", "attribute"); } auto getShadingDefine = [](Shading shading) -> const char* { diff --git a/shaders/src/post_process_inputs.vs b/shaders/src/post_process_inputs.vs index 1bbb1256a0..8b51a54234 100644 --- a/shaders/src/post_process_inputs.vs +++ b/shaders/src/post_process_inputs.vs @@ -1,4 +1,4 @@ -LAYOUT_LOCATION(LOCATION_POSITION) in vec4 position; +LAYOUT_LOCATION(LOCATION_POSITION) ATTRIBUTE vec4 position; struct PostProcessVertexInputs {