| diff --git a/.gitignore b/.gitignore |
| index 67fe31af474d781541a19e3206e05a047312e609..f4c65edc4f421263e4a7547beeb83054fb725dc5 100644 |
| --- a/.gitignore |
| +++ b/.gitignore |
| @@ -97,7 +97,37 @@ |
| /third_party/spirv-tools/src |
| /third_party/SwiftShader |
| /third_party/turbine/cipd |
| -/third_party/VK-GL-CTS/src |
| +/third_party/VK-GL-CTS/src/* |
| +!/third_party/VK-GL-CTS/src/framework |
| +!/third_party/VK-GL-CTS/src/execserver |
| +!/third_party/VK-GL-CTS/src/executor |
| +!/third_party/VK-GL-CTS/src/modules |
| +/third_party/VK-GL-CTS/src/modules/* |
| +!/third_party/VK-GL-CTS/src/modules/gles2 |
| +!/third_party/VK-GL-CTS/src/modules/gles3 |
| +!/third_party/VK-GL-CTS/src/modules/glshared |
| +!/third_party/VK-GL-CTS/src/data |
| +/third_party/VK-GL-CTS/src/data/* |
| +!/third_party/VK-GL-CTS/src/data/gles2 |
| +!/third_party/VK-GL-CTS/src/data/gles3 |
| +# Drill down to the two GLES2/GLES3 mustpass case lists the runner reads (the |
| +# rest of external/openglcts stays ignored). Each parent dir is re-included so |
| +# git descends to the files; one recursive exclude keeps everything else out |
| +# (a plain ignore of external would stop git descending -- nested re-includes |
| +# then have no effect; re-including ALL dirs would drag in upstream's own nested |
| +# .gitignore files, so only the dirs on the path are re-included). |
| +!/third_party/VK-GL-CTS/src/external |
| +/third_party/VK-GL-CTS/src/external/** |
| +!/third_party/VK-GL-CTS/src/external/openglcts |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts/data |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts/data/mustpass |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts/data/mustpass/gles |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts/data/mustpass/gles/aosp_mustpass |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts/data/mustpass/gles/aosp_mustpass/main |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts/data/mustpass/gles/aosp_mustpass/main/gles2-main.txt |
| +!/third_party/VK-GL-CTS/src/external/openglcts/data/gl_cts/data/mustpass/gles/aosp_mustpass/main/gles3-main.txt |
| /third_party/vulkan-deps |
| /third_party/vulkan-headers/src |
| /third_party/vulkan-loader/src |
| diff --git a/additional_readme_paths.json b/additional_readme_paths.json |
| deleted file mode 100644 |
| index 453a20a2f4c0b7c0233c2c636c174816d03b7cd4..0000000000000000000000000000000000000000 |
| --- a/additional_readme_paths.json |
| +++ /dev/null |
| @@ -1,4 +0,0 @@ |
| -[ |
| - "src/common/third_party/xxhash", |
| - "src/libANGLE/renderer/vulkan/shaders/src/third_party/ffx_spd" |
| -] |
| diff --git a/doc/ExtensionSupport.md b/doc/ExtensionSupport.md |
| index 075233f7ffa87b64e946177349db801f1c597f8b..fe01c638d716e5d2e0c24e94c158990610763c2d 100644 |
| --- a/doc/ExtensionSupport.md |
| +++ b/doc/ExtensionSupport.md |
| @@ -237,6 +237,7 @@ using data from registry_xml.py and gl.xml. |
| | [GL_CHROMIUM_copy_compressed_texture](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/CHROMIUM_copy_compressed_texture.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| | [GL_CHROMIUM_copy_texture](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/CHROMIUM_copy_texture.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| | [GL_ANGLE_copy_texture_3d](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_copy_texture_3d.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| +| [GL_WEBKIT_explicit_resolve_target](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/WEBKIT_explicit_resolve_target.txt) | | | | | | | | |
| | [GL_CHROMIUM_framebuffer_mixed_samples](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/CHROMIUM_framebuffer_mixed_samples.txt) | | | | | | | | |
| | [GL_ANGLE_framebuffer_multisample](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_framebuffer_multisample.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| | [GL_ANGLE_get_image](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_get_image.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| @@ -271,6 +272,7 @@ using data from registry_xml.py and gl.xml. |
| | [GL_ANGLE_texture_compression_dxt5](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_texture_compression_dxt5.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | | | |
| | [GL_ANGLE_texture_multisample](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_texture_multisample.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| | [GL_ANGLE_texture_rectangle](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_texture_rectangle.txt) | | | | | | | | |
| +| [GL_ANGLE_variable_rasterization_rate_metal](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_variable_rasterization_rate_metal.txt) | | | | | | | | |
| | [GL_ANGLE_vulkan_image](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_vulkan_image.txt) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | |
| | [GL_ANGLE_webgl_compatibility](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_webgl_compatibility.txt) | | | | | | | | |
| | [GL_ANGLE_yuv_internal_format](https://chromium.googlesource.com/angle/angle/+/refs/heads/main/extensions/ANGLE_yuv_internal_format.txt) | ✔ | | ✔ | ✔ | ✔ | ✔ | ✔ | |
| diff --git a/include/GLES2/gl2ext_angle.h b/include/GLES2/gl2ext_angle.h |
| index 6c3ffca06c05d7d427acdef42a2762e2889b0518..8dc1110453fdb99100c7b580d8728b6acd406569 100644 |
| --- a/include/GLES2/gl2ext_angle.h |
| +++ b/include/GLES2/gl2ext_angle.h |
| @@ -715,5 +715,23 @@ GL_APICALL void GL_APIENTRY glGetPointervANGLE (GLenum pname, void **params); |
| #endif |
| #endif /* GL_ANGLE_blob_cache */ |
| |
| +#ifndef GL_WEBKIT_explicit_resolve_target |
| +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC) (GLenum, GLenum, GLenum, GLuint); |
| +#ifdef GL_GLEXT_PROTOTYPES |
| +GL_APICALL void GL_APIENTRY glFramebufferResolveRenderbufferWEBKIT(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); |
| +#endif |
| +#endif /* GL_WEBKIT_explicit_resolve_target */ |
| + |
| +#ifndef GL_ANGLE_variable_rasterization_rate_metal |
| +#define GL_ANGLE_variable_rasterization_rate_metal 1 |
| + |
| +#define GL_VARIABLE_RASTERIZATION_RATE_ANGLE 0x96BC |
| +#define GL_METAL_RASTERIZATION_RATE_MAP_BINDING_ANGLE 0x96BD |
| +typedef void *GLMTLRasterizationRateMapANGLE; |
| +typedef void (GL_APIENTRYP PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC) (GLuint, GLMTLRasterizationRateMapANGLE); |
| +#ifdef GL_GLEXT_PROTOTYPES |
| +GL_APICALL void GL_APIENTRY glBindMetalRasterizationRateMapANGLE(GLuint framebuffer, GLMTLRasterizationRateMapANGLE map); |
| +#endif |
| +#endif /* GL_ANGLE_variable_rasterization_rate_metal */ |
| |
| #endif // INCLUDE_GLES2_GL2EXT_ANGLE_H_ |
| diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h |
| index 6ff1943f55d260981786b39d81aa0cc952440300..69dd4a0e97f6b228a269bcd993d15de2d8a94644 100644 |
| --- a/include/GLSLANG/ShaderLang.h |
| +++ b/include/GLSLANG/ShaderLang.h |
| @@ -161,8 +161,8 @@ struct ShPixelLocalStorageOptions |
| struct ShCompileOptions |
| { |
| ShCompileOptions(); |
| - ShCompileOptions(const ShCompileOptions &other); |
| - ShCompileOptions &operator=(const ShCompileOptions &other); |
| + ShCompileOptions(const ShCompileOptions &other) = default; |
| + ShCompileOptions &operator=(const ShCompileOptions &other) = default; |
| |
| // Translates intermediate tree to glsl, hlsl, msl, or SPIR-V binary. Can be queried by |
| // calling sh::GetObjectCode(). |
| @@ -497,8 +497,8 @@ using ShHashFunction64 = khronos_uint64_t (*)(const char *, size_t); |
| struct ShBuiltInResources |
| { |
| ShBuiltInResources(); |
| - ShBuiltInResources(const ShBuiltInResources &other); |
| - ShBuiltInResources &operator=(const ShBuiltInResources &other); |
| + ShBuiltInResources(const ShBuiltInResources &) = default; |
| + ShBuiltInResources &operator=(const ShBuiltInResources &) = default; |
| |
| // Constants. |
| int MaxVertexAttribs; |
| diff --git a/include/platform/autogen/FeaturesMtl_autogen.h b/include/platform/autogen/FeaturesMtl_autogen.h |
| index 202f71c61a206841cfd02999b595937af049eda0..1015f88761ff9c0cf780490e7f88396141a5e349 100644 |
| --- a/include/platform/autogen/FeaturesMtl_autogen.h |
| +++ b/include/platform/autogen/FeaturesMtl_autogen.h |
| @@ -74,6 +74,12 @@ struct FeaturesMtl : FeatureSetBase |
| &members, |
| }; |
| |
| + FeatureInfo hasVariableRasterizationRate = { |
| + "hasVariableRasterizationRate", |
| + FeatureCategory::MetalFeatures, |
| + &members, |
| + }; |
| + |
| FeatureInfo allowInlineConstVertexData = { |
| "allowInlineConstVertexData", |
| FeatureCategory::MetalFeatures, |
| @@ -176,6 +182,12 @@ struct FeaturesMtl : FeatureSetBase |
| &members, |
| }; |
| |
| + FeatureInfo clearMsaaRg16UnormWithDrawWorkaround = { |
| + "clearMsaaRg16UnormWithDrawWorkaround", |
| + FeatureCategory::MetalWorkarounds, |
| + &members, |
| + }; |
| + |
| FeatureInfo copyIOSurfaceToNonIOSurfaceForReadOptimization = { |
| "copyIOSurfaceToNonIOSurfaceForReadOptimization", |
| FeatureCategory::MetalWorkarounds, |
| diff --git a/include/platform/mtl_features.json b/include/platform/mtl_features.json |
| index 78f0cbc10a3ce09a2d2d8d2d48d8a9d5766f1203..8da45c8ba0c31420aceec6ec82bc54429756570e 100644 |
| --- a/include/platform/mtl_features.json |
| +++ b/include/platform/mtl_features.json |
| @@ -70,6 +70,13 @@ |
| "The renderer supports MTL(Shared)Event" |
| ] |
| }, |
| + { |
| + "name": "has_variable_rasterization_rate", |
| + "category": "Features", |
| + "description": [ |
| + "The renderer supports variable rasterization rate" |
| + ] |
| + }, |
| { |
| "name": "allow_inline_const_vertex_data", |
| "category": "Features", |
| @@ -193,6 +200,16 @@ |
| ], |
| "issue": "http://anglebug.com/42265518" |
| }, |
| + { |
| + "name": "clear_msaa_rg16_unorm_with_draw_workaround", |
| + "category": "Workarounds", |
| + "description": [ |
| + "AMD Metal driver silently drops MTLLoadActionClear for MSAA RG16Unorm color ", |
| + "attachments at certain attachment indices. Force such clears through a ", |
| + "draw-call-based clear path instead of the load-action path." |
| + ], |
| + "issue": "rdar://178796612" |
| + }, |
| { |
| "name": "copy_IOSurface_to_non_IOSurface_for_read_optimization", |
| "category": "Workarounds", |
| diff --git a/scripts/code_generation_hashes/ANGLE_shader_preprocessor.json b/scripts/code_generation_hashes/ANGLE_shader_preprocessor.json |
| index de0ca8f77984dacc4db9aa7b3600ab517648a70f..01d8452bb759de83fadb0a80a711a10f43e1d7be 100644 |
| --- a/scripts/code_generation_hashes/ANGLE_shader_preprocessor.json |
| +++ b/scripts/code_generation_hashes/ANGLE_shader_preprocessor.json |
| @@ -1,16 +1,16 @@ |
| { |
| "src/compiler/generate_parser_tools.py": |
| - "bb5b9d7e3b890ad55fe9dba470cd86fe", |
| + "b2d9f7155fabd2391545e23d96b8094f", |
| "src/compiler/preprocessor/generate_parser.py": |
| "9a4588fdf009298fe49c52b9252789c7", |
| "src/compiler/preprocessor/preprocessor.l": |
| - "dc2261e73ea92b35d68d69748c341319", |
| + "3a70c749924f7093140ea30500033fb6", |
| "src/compiler/preprocessor/preprocessor.y": |
| "8e4f866302395b2e2e504d8f079a6631", |
| "src/compiler/preprocessor/preprocessor_lex_autogen.cpp": |
| - "c58edcc71ed87ab9613539a3acd5e194", |
| + "d46c244567fe4ee5c593b6fb247e7614", |
| "src/compiler/preprocessor/preprocessor_tab_autogen.cpp": |
| - "000f93c6b244dcae862efa319a737a7f", |
| + "ff3120300799cd96965e4c424b2d2ffb", |
| "tools/flex-bison/linux/bison.sha1": |
| "dfc9209e0c76eddd9bed0601c6c189e5", |
| "tools/flex-bison/linux/flex.sha1": |
| diff --git a/scripts/code_generation_hashes/ANGLE_shader_translator.json b/scripts/code_generation_hashes/ANGLE_shader_translator.json |
| index 28eca37ab7887cfaf8bfb859e4cb339e4931d448..7c792aa8bbb7e60330c43fc55e99ddcbf2a0b3a8 100644 |
| --- a/scripts/code_generation_hashes/ANGLE_shader_translator.json |
| +++ b/scripts/code_generation_hashes/ANGLE_shader_translator.json |
| @@ -1,18 +1,18 @@ |
| { |
| "src/compiler/generate_parser_tools.py": |
| - "bb5b9d7e3b890ad55fe9dba470cd86fe", |
| + "b2d9f7155fabd2391545e23d96b8094f", |
| "src/compiler/translator/generate_parser.py": |
| "ad919972a040d9b3b4aa5dc547fadc75", |
| "src/compiler/translator/glslang.l": |
| - "acb74a06d21b8835358767235beb969a", |
| + "b224e7a86bffef3b15c2e950c8f9e39e", |
| "src/compiler/translator/glslang.y": |
| "c1e72fcb5ff3371f21e66092351059bd", |
| "src/compiler/translator/glslang_lex_autogen.cpp": |
| - "47e19f00c1734935c48daffb011ff7f2", |
| + "de44fef5519954676c5628dd465ae8d8", |
| "src/compiler/translator/glslang_tab_autogen.cpp": |
| - "a678256fe6caaa595b5ab4e40453baa4", |
| + "099802556ab41e02fa94520d9d924e65", |
| "src/compiler/translator/glslang_tab_autogen.h": |
| - "028bdaebf359aefbcdaafae466993ebe", |
| + "11aef96205adbc2809c6652e099ccaa7", |
| "tools/flex-bison/linux/bison.sha1": |
| "dfc9209e0c76eddd9bed0601c6c189e5", |
| "tools/flex-bison/linux/flex.sha1": |
| diff --git a/scripts/code_generation_hashes/Extension_files.json b/scripts/code_generation_hashes/Extension_files.json |
| index f63c1220ee595b62fbca19e94bf98f0d4d7225c2..9ba116975090b5faa966e48421735d23664ac875 100644 |
| --- a/scripts/code_generation_hashes/Extension_files.json |
| +++ b/scripts/code_generation_hashes/Extension_files.json |
| @@ -1,6 +1,6 @@ |
| { |
| "doc/ExtensionSupport.md": |
| - "6aed84db027bb166284860a46e9b6503", |
| + "bb2e65a3da4888fe20b7bc69c9bbc2ff", |
| "scripts/egl_angle_ext.xml": |
| "676627eae49a3ccadeafc3adbd7dba8d", |
| "scripts/extension_data/intel_630_linux.json": |
| @@ -20,15 +20,15 @@ |
| "scripts/extension_data/swiftshader_win10_gles1.json": |
| "bea8e2106d62e1ea0e8938f150865a37", |
| "scripts/gl_angle_ext.xml": |
| - "b05697989dfe0eb4d714d537b80e8295", |
| + "d32731daaf2540f863533d09838b8065", |
| "scripts/registry_xml.py": |
| - "ec48910a40247a09fc5de73b0142e4af", |
| + "ba95a9e96754b2cbe25f15823abae054", |
| "src/libANGLE/gen_extensions.py": |
| "b633607f7ec8333cd64234e5e10af145", |
| "src/libANGLE/gles_extensions_autogen.cpp": |
| - "753da7e80c748e6498d4d209030cd700", |
| + "99e90413b629f1ec37d9591593f8b682", |
| "src/libANGLE/gles_extensions_autogen.h": |
| - "33cde27be77eeca5e080c37ef7577511", |
| + "d47f3f98aa6223ac4c8a259aee06ddb4", |
| "third_party/EGL-Registry/src/api/egl.xml": |
| "2056d54ea07156f1988ca1366bdee21a", |
| "third_party/OpenCL-Docs/src/xml/cl.xml": |
| diff --git a/scripts/code_generation_hashes/GL_CTS_(dEQP)_build_files.json b/scripts/code_generation_hashes/GL_CTS_(dEQP)_build_files.json |
| index ea377772478807851fc9346870fa4b9efed78471..015eee691619099bae5b69a0f477b4c26789abfa 100644 |
| --- a/scripts/code_generation_hashes/GL_CTS_(dEQP)_build_files.json |
| +++ b/scripts/code_generation_hashes/GL_CTS_(dEQP)_build_files.json |
| @@ -11,166 +11,8 @@ |
| "38aa187592e6ef9a331fc1ea313fc68d", |
| "third_party/VK-GL-CTS/src/executor/CMakeLists.txt": |
| "6b76472709cd27e9e541f7b4ed9ed028", |
| - "third_party/VK-GL-CTS/src/external/amber/CMakeLists.txt": |
| - "8871068a2efa10bdce22d5a8588db7ab", |
| - "third_party/VK-GL-CTS/src/external/glslang/CMakeLists.txt": |
| - "702c2f212d8f4442e3c307eb451201de", |
| - "third_party/VK-GL-CTS/src/external/jsoncpp/CMakeLists.txt": |
| - "6783933d4178dbe4a8328a9dce4fa3b1", |
| - "third_party/VK-GL-CTS/src/external/libpng/CMakeLists.txt": |
| - "fb1d65fa30f92dc2368c8d952947e95e", |
| "third_party/VK-GL-CTS/src/external/openglcts/CMakeLists.txt": |
| "eb5ba40db4ae92a7ced48b16329afbb6", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/CMakeLists.txt": |
| - "6b87a3cf65a8eb5506a87fa1049e752e", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/common/CMakeLists.txt": |
| - "397e09a957da589ffd561a4d30bcab6d", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/common/meshShader/CMakeLists.txt": |
| - "04532172e252ad28f96de597586cf073", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/common/subgroups/CMakeLists.txt": |
| - "bf71ce2d9756ccee7833a789737e6481", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/gl/CMakeLists.txt": |
| - "6ea9e3f13f5f653627d793fd23a9b734", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/gles2/CMakeLists.txt": |
| - "5ac63dce60849bf12e3ab2dde99424ab", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/gles3/CMakeLists.txt": |
| - "f43062e027a78f04932dc8e9f6342c40", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/gles31/CMakeLists.txt": |
| - "fb64f59b937c74e4181ff2eb0a7facc3", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/gles32/CMakeLists.txt": |
| - "f2e02e3f357ad23b037f028efb744fe4", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/glesext/CMakeLists.txt": |
| - "9e78c7857b44973b82cb44c3815e7b4e", |
| - "third_party/VK-GL-CTS/src/external/openglcts/modules/runner/CMakeLists.txt": |
| - "3dcd5a676779022e768aaa35e286757d", |
| - "third_party/VK-GL-CTS/src/external/spirv-tools/CMakeLists.txt": |
| - "cca8b4b984c40afb9880d177d53623a1", |
| - "third_party/VK-GL-CTS/src/external/video_generator/CMakeLists.txt": |
| - "b1160ff12fbe868ec874a8510e94b537", |
| - "third_party/VK-GL-CTS/src/external/vulkan-validationlayers/CMakeLists.txt": |
| - "53b56df74a8a4ac5ae1cedcbb1ff440f", |
| - "third_party/VK-GL-CTS/src/external/vulkan-video-samples/CMakeLists.txt": |
| - "620a4f4d6962cb9a300a31be329b3b2a", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/framework/vulkan/CMakeLists.txt": |
| - "0139e89b14acf44e1688127c3bf5c9da", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/CMakeLists.txt": |
| - "0373c12ffe45746b288811c033013eef", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/amber/CMakeLists.txt": |
| - "51aed6000e6c76f2e4a5922e48841885", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/api/CMakeLists.txt": |
| - "085a1e83e9bc23cf6903728dea3c391f", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/binding_model/CMakeLists.txt": |
| - "b417e15e2d9d5d13fca3ee7f74d0002d", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/clipping/CMakeLists.txt": |
| - "2341f788b087bc78e89f66446fdad59b", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/compute/CMakeLists.txt": |
| - "45c0c14e37959ad81c05c6e276a121e2", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/conditional_rendering/CMakeLists.txt": |
| - "933be687f555f0fe1dc061c270cc9aa6", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/cooperative_vector/CMakeLists.txt": |
| - "7c0e5da40f80c2b1045cc16fc70b893c", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/data_graph/CMakeLists.txt": |
| - "59ab713400bedf547332a2fd8fb887a4", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/descriptor_indexing/CMakeLists.txt": |
| - "32f809fa5ec2534a5567ce5f42d7a685", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/device_generated_commands/CMakeLists.txt": |
| - "8ba06f20e6ee76bb0d6ad48be9fbf3ed", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/device_group/CMakeLists.txt": |
| - "451a6c35fd38aec3212d02f14f201cf9", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/draw/CMakeLists.txt": |
| - "818867011729459b85e7d20dfa47c6e5", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/dynamic_state/CMakeLists.txt": |
| - "3db8818671533ace06b9b7710aeda461", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/fragment_ops/CMakeLists.txt": |
| - "f1e720b1aa67ec3a3dc981369910e6cd", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/fragment_shader_interlock/CMakeLists.txt": |
| - "70739d786729b1bfaddeb1c93dec41f0", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/fragment_shading_barycentric/CMakeLists.txt": |
| - "994299a54be2b1fd84770b5b1b1e27d6", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/fragment_shading_rate/CMakeLists.txt": |
| - "70bd1230fad695239b2a5e9019737eaf", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/geometry/CMakeLists.txt": |
| - "335903779295e9652fdfccde1f9a2078", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/image/CMakeLists.txt": |
| - "a81aea82a145ab03d30574f8acca8387", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/image_processing/CMakeLists.txt": |
| - "2a5340e24a562a513a4a4223b02c66c0", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/imageless_framebuffer/CMakeLists.txt": |
| - "62bd75a001d0e25016bcac31c1fbbfa8", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/memory/CMakeLists.txt": |
| - "2c415a960cea84e8df22d6a0eb17d86c", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/memory_model/CMakeLists.txt": |
| - "e3000d0283ba5aa213921ef32c707b64", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/mesh_shader/CMakeLists.txt": |
| - "cb0f508bca3d9f90bd1a403fc1899900", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/modifiers/CMakeLists.txt": |
| - "471241670f8384908630cb1c491c3d54", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/multiview/CMakeLists.txt": |
| - "e426e46a5ad0be2fbc7391bb6d9efc75", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/pipeline/CMakeLists.txt": |
| - "14994ab8c7573f7821315c42c760d31c", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/postmortem/CMakeLists.txt": |
| - "701b4a0c61cf94fa3cf44a6017496562", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/protected_memory/CMakeLists.txt": |
| - "57966bb46c3156d090443753a38ee0ac", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/query_pool/CMakeLists.txt": |
| - "6fd3194185b50f25949aa0635cbebeeb", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/rasterization/CMakeLists.txt": |
| - "20691d4d355ac09d18b98f0c8e184842", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/ray_query/CMakeLists.txt": |
| - "e2e1ca16288794542a6da7d323bc2844", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/ray_tracing/CMakeLists.txt": |
| - "0da2e61cac18a192686332ac4d24c314", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/reconvergence/CMakeLists.txt": |
| - "c00ddc8833c41b98d0d70e2067f1c08b", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/renderpass/CMakeLists.txt": |
| - "b3b6f371d407aad8741b6fc3ac249a83", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/robustness/CMakeLists.txt": |
| - "643240ef59da29b16b9ad3882d338f6e", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/sc/CMakeLists.txt": |
| - "59984e5eeb9a42789bd499b24b45fdc9", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/shader_object/CMakeLists.txt": |
| - "5992d8d787569663fcf4c780c19b0cdc", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt": |
| - "b454631bc58923238e5e3eedd4fe496c", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/shaderrender/CMakeLists.txt": |
| - "aed26ad8bba3ae469bde60b6fccc5d4e", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/sparse_resources/CMakeLists.txt": |
| - "965e2b61b0d71a751dedafc771f9a6b2", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/spirv_assembly/CMakeLists.txt": |
| - "e73b9d85e1e5398833cc360e8751339d", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/ssbo/CMakeLists.txt": |
| - "d55fb16baef897474f99294e88fd6300", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/subgroups/CMakeLists.txt": |
| - "5da8e2fa227c4f18504e4b511e1390e7", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/synchronization/CMakeLists.txt": |
| - "4166a007b65a7ab34b7a90c6b734401a", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/tensor/CMakeLists.txt": |
| - "e9b17dee83247c5dd83a3aebe8ac8b31", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/tessellation/CMakeLists.txt": |
| - "ce33d79ab4c6522f0d25db75c7959089", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/texture/CMakeLists.txt": |
| - "12a01bae782a7fb371d76d4d943e680f", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/transform_feedback/CMakeLists.txt": |
| - "9beae6ed8f1fbd14c7351184065a4a99", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/ubo/CMakeLists.txt": |
| - "b19406c9adcf4f085868da42a6910ee5", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/util/CMakeLists.txt": |
| - "91d17e85771f10651a62d757da9e1bb1", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/video/CMakeLists.txt": |
| - "89aafa542376271f90f645676a695a21", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/wsi/CMakeLists.txt": |
| - "dff13488a8423c7a4bc7f11b4f777ddc", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/modules/vulkan/ycbcr/CMakeLists.txt": |
| - "0ef63427b2fb168abd931ae5966f7200", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/vkscpc/CMakeLists.txt": |
| - "b1e0a3495cabd10a8020bf0aa2635ee1", |
| - "third_party/VK-GL-CTS/src/external/vulkancts/vkscserver/CMakeLists.txt": |
| - "00150c0a7b5c3da7923dfcfa9292ad69", |
| - "third_party/VK-GL-CTS/src/external/vulkansc-pcutil/CMakeLists.txt": |
| - "301160e312c78d27ddac8950c30bd2d1", |
| - "third_party/VK-GL-CTS/src/external/zlib/CMakeLists.txt": |
| - "30ffe3a360ab8870fe103084e9947e6d", |
| "third_party/VK-GL-CTS/src/framework/CMakeLists.txt": |
| "edeee2284578f1b76122adee5e42f0e7", |
| "third_party/VK-GL-CTS/src/framework/common/CMakeLists.txt": |
| @@ -211,8 +53,6 @@ |
| "58c91860abe3f6515acbf5a5abce6f0c", |
| "third_party/VK-GL-CTS/src/modules/CMakeLists.txt": |
| "632cf1d4d696b1e19c01c6d11e2d59c4", |
| - "third_party/VK-GL-CTS/src/modules/egl/CMakeLists.txt": |
| - "56b1b9e93a8c761c1b91fd4c2992e630", |
| "third_party/VK-GL-CTS/src/modules/gles2/CMakeLists.txt": |
| "ec93c8c562e1e87d77e7b024d02e0e07", |
| "third_party/VK-GL-CTS/src/modules/gles2/accuracy/CMakeLists.txt": |
| @@ -233,14 +73,6 @@ |
| "7f59f06951811838d837912e366f1223", |
| "third_party/VK-GL-CTS/src/modules/gles3/stress/CMakeLists.txt": |
| "618e03b394cfc824a5114e7c0ac9843e", |
| - "third_party/VK-GL-CTS/src/modules/gles31/CMakeLists.txt": |
| - "fb5c020dd76bd615510e1ebfaaa8a19c", |
| - "third_party/VK-GL-CTS/src/modules/gles31/functional/CMakeLists.txt": |
| - "5c3b539f7a48f1e754d4e338d4c6cd71", |
| - "third_party/VK-GL-CTS/src/modules/gles31/stress/CMakeLists.txt": |
| - "d7ce9c1931444d263a0af3dcc5a11090", |
| "third_party/VK-GL-CTS/src/modules/glshared/CMakeLists.txt": |
| - "97bd9c51fa33d2231ff158a913e1e486", |
| - "third_party/VK-GL-CTS/src/modules/internal/CMakeLists.txt": |
| - "3a2216627b43341eac2615c958b8290b" |
| + "97bd9c51fa33d2231ff158a913e1e486" |
| } |
| diff --git a/scripts/code_generation_hashes/GL_EGL_WGL_loader.json b/scripts/code_generation_hashes/GL_EGL_WGL_loader.json |
| index f0c877b27c68678bf8d642df20b00768e15295e5..cef0ce2c7022723d8e9446b12ce834d928035549 100644 |
| --- a/scripts/code_generation_hashes/GL_EGL_WGL_loader.json |
| +++ b/scripts/code_generation_hashes/GL_EGL_WGL_loader.json |
| @@ -4,9 +4,9 @@ |
| "scripts/generate_loader.py": |
| "93c78a8d11323fa311fed5118fbcf083", |
| "scripts/gl_angle_ext.xml": |
| - "b05697989dfe0eb4d714d537b80e8295", |
| + "d32731daaf2540f863533d09838b8065", |
| "scripts/registry_xml.py": |
| - "ec48910a40247a09fc5de73b0142e4af", |
| + "ba95a9e96754b2cbe25f15823abae054", |
| "src/libEGL/egl_loader_autogen.cpp": |
| "2aca2a57c51fc2b1c7e1da0a7ccf6107", |
| "src/libEGL/egl_loader_autogen.h": |
| @@ -26,17 +26,17 @@ |
| "util/capture/trace_egl_loader_autogen.h": |
| "9adc81af729078b16b36647f02401342", |
| "util/capture/trace_gles_loader_autogen.cpp": |
| - "753464954e79fe5ea472a4a0487c1760", |
| + "20566420dd93a80ff0a204afc1db9ffb", |
| "util/capture/trace_gles_loader_autogen.h": |
| - "2ec52563851a50ba3fdae94708b19f19", |
| + "79a331cbad36eb8e4907c6c0935de2a8", |
| "util/egl_loader_autogen.cpp": |
| "ae6abfc6c2c0a997ad59258dfc0339ce", |
| "util/egl_loader_autogen.h": |
| "ea5f73048616a6fc80eaa7e93ef5f0ce", |
| "util/gles_loader_autogen.cpp": |
| - "b503542943682871acf8ed42d15f5061", |
| + "09dc1ed6573948ee1ac47d57386c28a3", |
| "util/gles_loader_autogen.h": |
| - "6e309d71b0369730d53e3299f5b973e7", |
| + "bd6d68ef0d92847edf0325d32de8bb06", |
| "util/windows/wgl_loader_autogen.cpp": |
| "373b062587eab8a163121255f54597dc", |
| "util/windows/wgl_loader_autogen.h": |
| diff --git a/scripts/code_generation_hashes/GL_EGL_entry_points.json b/scripts/code_generation_hashes/GL_EGL_entry_points.json |
| index 1205985a2b7ff76f40fb84ffcc7d55a3c8fb83f6..6230a89faa8fba9908eceeab479af5082c74af75 100644 |
| --- a/scripts/code_generation_hashes/GL_EGL_entry_points.json |
| +++ b/scripts/code_generation_hashes/GL_EGL_entry_points.json |
| @@ -4,21 +4,21 @@ |
| "scripts/entry_point_packed_egl_enums.json": |
| "a72ae855c6b403912103b519139951a1", |
| "scripts/entry_point_packed_gl_enums.json": |
| - "5796eeaa1b8aaff4eecaa6a72eca158e", |
| + "c14434707d630300965ce9ce65b19979", |
| "scripts/generate_entry_points.py": |
| - "1d6703fdf1078902b8124aa4c32d084e", |
| + "b3ed40534ed145fa6b61634f658b443b", |
| "scripts/gl_angle_ext.xml": |
| - "b05697989dfe0eb4d714d537b80e8295", |
| + "d32731daaf2540f863533d09838b8065", |
| "scripts/registry_xml.py": |
| - "ec48910a40247a09fc5de73b0142e4af", |
| + "ba95a9e96754b2cbe25f15823abae054", |
| "src/common/entry_points_enum_autogen.cpp": |
| - "40a59d775f45b44ef5772aaca290d182", |
| + "5bb32b8a64a7254204f8651b0d64d731", |
| "src/common/entry_points_enum_autogen.h": |
| - "abb888c602873cdc5015230328e47de1", |
| + "a970cb0897d5b4920aa8ff1e99f29150", |
| "src/common/frame_capture_utils_autogen.cpp": |
| - "8afc9201defecb58a88baac123d44905", |
| + "654590405ff591ea0bdb179634bbe4e6", |
| "src/common/frame_capture_utils_autogen.h": |
| - "f43d34d280226a5678fe068d2ba69e08", |
| + "17cf2f38f41d9163260f7b8c6cdc116b", |
| "src/libANGLE/Context_gles_1_0_autogen.h": |
| "764a308a2ab21ca686f1157820ae529b", |
| "src/libANGLE/Context_gles_2_0_autogen.h": |
| @@ -30,7 +30,7 @@ |
| "src/libANGLE/Context_gles_3_2_autogen.h": |
| "2c9c311770948eff8e705e8f571b706a", |
| "src/libANGLE/Context_gles_ext_autogen.h": |
| - "a277697353337bc710f4e5d3f6cedb37", |
| + "9c6c2112ff513edf2c4cb8d74576e5fe", |
| "src/libANGLE/capture/capture_cl_autogen.cpp": |
| "a391fcabc30b0e1811f89e18cee4683f", |
| "src/libANGLE/capture/capture_cl_autogen.h": |
| @@ -60,9 +60,9 @@ |
| "src/libANGLE/capture/capture_gles_3_2_autogen.h": |
| "b7b82465a98fc2d9e2d3e3a75d49b94c", |
| "src/libANGLE/capture/capture_gles_ext_autogen.cpp": |
| - "4b7edc72f3c7e2123c668bbaf5fe1db2", |
| + "3f8ef25f7b54b0cae7507ba4d84df4f5", |
| "src/libANGLE/capture/capture_gles_ext_autogen.h": |
| - "6b50a5e782dd7c5eea1f3a8c4ab09727", |
| + "a2fc329de8677a729a2c259fdb6308f8", |
| "src/libANGLE/context_private_call_autogen.h": |
| "6e1862b4b4e8b1b23ab6f10f50d685b8", |
| "src/libANGLE/validationCL_autogen.h": |
| @@ -80,7 +80,7 @@ |
| "src/libANGLE/validationES3_autogen.h": |
| "a9c304e2e8ec7f6bd4cd71003fbbeec4", |
| "src/libANGLE/validationESEXT_autogen.h": |
| - "140948598e92d9077717c5bc1d1f01a9", |
| + "1e123097065b0ff2ead8bdee2af7e8d7", |
| "src/libEGL/libEGL_autogen.cpp": |
| "8c9edded59d8f12df7e6bb422763adad", |
| "src/libEGL/libEGL_autogen.def": |
| @@ -130,19 +130,19 @@ |
| "src/libGLESv2/entry_points_gles_3_2_autogen.h": |
| "647f932a299cdb4726b60bbba059f0d2", |
| "src/libGLESv2/entry_points_gles_ext_autogen.cpp": |
| - "494ae92a0c896332758948da3dbab3cc", |
| + "e89e72d0eea056f05391bf0897b78831", |
| "src/libGLESv2/entry_points_gles_ext_autogen.h": |
| - "7db866a3ee28a7274efdcbb2484ae6aa", |
| + "19a9e2699f274d7f07cab6183b8acb2f", |
| "src/libGLESv2/libGLESv2_autogen.cpp": |
| - "6366efb3f21f1a49c98d9d8f32c5a6ee", |
| + "4cdeb2b34f2ae2a3b478736ca53f2c8b", |
| "src/libGLESv2/libGLESv2_autogen.def": |
| - "334a51e922c415ca841bbae6dbaba2bc", |
| + "811811e68db177c37b5354b5937f36a8", |
| "src/libGLESv2/libGLESv2_no_capture_autogen.def": |
| - "c524f25bc6661f9d4dcdede837d7e81c", |
| + "dc1e1e21427ea9e20ebfcfe59851e4c0", |
| "src/libGLESv2/libGLESv2_vulkan_secondaries_autogen.def": |
| - "7ee469acacb6ea59bbb7ae3c77f0f4ed", |
| + "8199aa933d15af725783d2709a037140", |
| "src/libGLESv2/libGLESv2_with_capture_autogen.def": |
| - "2298adcb1dd4a520385ac3088483b0a9", |
| + "2af868aea33ebb6158054070408aae4b", |
| "src/libOpenCL/libOpenCL_autogen.cpp": |
| "b269a634d29f84fbc570b5ceca4ded04", |
| "third_party/EGL-Registry/src/api/egl.xml": |
| @@ -156,5 +156,5 @@ |
| "third_party/OpenGL-Registry/src/xml/wgl.xml": |
| "53f90180449a1abcd8fdfe56fc5c869c", |
| "util/capture/frame_capture_replay_autogen.cpp": |
| - "d32127162519e9c2ac96c41281953e53" |
| + "985bad43633681b8a446d0724cbab9b7" |
| } |
| diff --git a/scripts/code_generation_hashes/GLenum_value_to_string_map.json b/scripts/code_generation_hashes/GLenum_value_to_string_map.json |
| index 51cd176b10120d5b423520709bf574d6dde1a315..b6f699d696e2daab1bb957e6f841492f1f8e31d6 100644 |
| --- a/scripts/code_generation_hashes/GLenum_value_to_string_map.json |
| +++ b/scripts/code_generation_hashes/GLenum_value_to_string_map.json |
| @@ -2,11 +2,11 @@ |
| "scripts/gen_gl_enum_utils.py": |
| "12506d2a222614dc840212e20c192450", |
| "scripts/gl_angle_ext.xml": |
| - "b05697989dfe0eb4d714d537b80e8295", |
| + "d32731daaf2540f863533d09838b8065", |
| "scripts/registry_xml.py": |
| - "ec48910a40247a09fc5de73b0142e4af", |
| + "ba95a9e96754b2cbe25f15823abae054", |
| "src/common/gl_enum_utils_autogen.cpp": |
| - "c8d753908272495a266bab15fa00511d", |
| + "acc17f655777651dc9ffc80f8e6ba83e", |
| "src/common/gl_enum_utils_autogen.h": |
| "2de2b2dfc98be173cc8d49dfc4a4510c", |
| "third_party/OpenGL-Registry/src/xml/gl.xml": |
| diff --git a/scripts/code_generation_hashes/Metal_default_shaders.json b/scripts/code_generation_hashes/Metal_default_shaders.json |
| index 68a851258b5b556d21ad8e23934926e6e41bf0bd..28ded15e57adefe3d406c0529da4f0fca1aab791 100644 |
| --- a/scripts/code_generation_hashes/Metal_default_shaders.json |
| +++ b/scripts/code_generation_hashes/Metal_default_shaders.json |
| @@ -22,11 +22,11 @@ |
| "src/libANGLE/renderer/metal/shaders/gen_mtl_internal_shaders.py": |
| "368cb14cf2005e682edc4d4afce8d7b9", |
| "src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_autogen.metal": |
| - "0b9c23d53bdc8739f660e492907bc494", |
| + "69f33e0edaa422f4030ed52164fb011a", |
| "src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_src_autogen.h": |
| - "9c768791b9d0a599e86e48c25663f62c", |
| + "b4f1011bb9dea2deab88d5877f1462ca", |
| "src/libANGLE/renderer/metal/shaders/rewrite_indices.metal": |
| - "94585ecc47d4baff8acb23e52fc85055", |
| + "e4083bd9a7e620b105e687f5080610af", |
| "src/libANGLE/renderer/metal/shaders/visibility.metal": |
| "b82aa740cf4b0aed606aacef1024beea" |
| } |
| diff --git a/scripts/code_generation_hashes/Metal_format_table.json b/scripts/code_generation_hashes/Metal_format_table.json |
| index a26294779477c3a621e473fc84940cd18eb80aac..983c9bf19530ed31fb1133d0b1027ef09922cf4e 100644 |
| --- a/scripts/code_generation_hashes/Metal_format_table.json |
| +++ b/scripts/code_generation_hashes/Metal_format_table.json |
| @@ -4,9 +4,9 @@ |
| "src/libANGLE/renderer/angle_format_map.json": |
| "abad08e462a0839d1600d83f83bcad8b", |
| "src/libANGLE/renderer/metal/gen_mtl_format_table.py": |
| - "552a693fc998b4c69d417f18c8f11887", |
| + "ec49e59aa8fe06b6aaa791bd2b9fa602", |
| "src/libANGLE/renderer/metal/mtl_format_map.json": |
| "cb72edc9237cf806792b2e4066a27627", |
| "src/libANGLE/renderer/metal/mtl_format_table_autogen.mm": |
| - "5e518281148d86f1fb0b90dd5d548e26" |
| + "7663a717e56d22922e54aa88e4962f23" |
| } |
| diff --git a/scripts/code_generation_hashes/interpreter_utils.json b/scripts/code_generation_hashes/interpreter_utils.json |
| index 23c861bbfd229457b8db8d805731357e3b8b4247..1d04845bfbd2f86b30edec556f75d800a0cc9228 100644 |
| --- a/scripts/code_generation_hashes/interpreter_utils.json |
| +++ b/scripts/code_generation_hashes/interpreter_utils.json |
| @@ -4,9 +4,9 @@ |
| "scripts/gen_interpreter_utils.py": |
| "7c21cda140a45527c02ddd003ebe7914", |
| "scripts/gl_angle_ext.xml": |
| - "b05697989dfe0eb4d714d537b80e8295", |
| + "d32731daaf2540f863533d09838b8065", |
| "scripts/registry_xml.py": |
| - "ec48910a40247a09fc5de73b0142e4af", |
| + "ba95a9e96754b2cbe25f15823abae054", |
| "third_party/EGL-Registry/src/api/egl.xml": |
| "2056d54ea07156f1988ca1366bdee21a", |
| "third_party/OpenCL-Docs/src/xml/cl.xml": |
| @@ -20,5 +20,5 @@ |
| "util/capture/trace_fixture.h": |
| "c8983a95f5c39cbc519e1cc8039b945b", |
| "util/capture/trace_interpreter_autogen.cpp": |
| - "20768ab22e9af4fa7fbf1a333cb16f04" |
| + "277b72d1be2208f3da081c9606b81f09" |
| } |
| diff --git a/scripts/code_generation_hashes/proc_table.json b/scripts/code_generation_hashes/proc_table.json |
| index c26a082c111db57f4d4a12a22274548dfc74f86e..c62822141635286e524a7fa1380ef36e0cf26214 100644 |
| --- a/scripts/code_generation_hashes/proc_table.json |
| +++ b/scripts/code_generation_hashes/proc_table.json |
| @@ -4,11 +4,11 @@ |
| "scripts/gen_proc_table.py": |
| "23ebf460dda78d2c21625e0d41d3cb97", |
| "scripts/gl_angle_ext.xml": |
| - "b05697989dfe0eb4d714d537b80e8295", |
| + "d32731daaf2540f863533d09838b8065", |
| "scripts/registry_xml.py": |
| - "ec48910a40247a09fc5de73b0142e4af", |
| + "ba95a9e96754b2cbe25f15823abae054", |
| "src/libGLESv2/egl_stubs_getprocaddress_autogen.cpp": |
| - "14d25131414811a8b4a1a36d23c5de27", |
| + "094f60d72fd627e1357df5d1ad9818a3", |
| "src/libGLESv2/proc_table_cl_autogen.cpp": |
| "c574d0cc27530b51e3fdc99b13bc740a", |
| "src/libOpenCL/libOpenCL_autogen.map": |
| diff --git a/scripts/entry_point_packed_gl_enums.json b/scripts/entry_point_packed_gl_enums.json |
| index 57124850a566b433d3d0e7e835217da2b86ccfb3..9e59a03c4f2b6379a2d1f3bd15aabec5f4254fd3 100644 |
| --- a/scripts/entry_point_packed_gl_enums.json |
| +++ b/scripts/entry_point_packed_gl_enums.json |
| @@ -440,6 +440,9 @@ |
| "glFramebufferFoveationParameters": { |
| "framebuffer": "FramebufferID" |
| }, |
| + "glFramebufferResolveRenderbufferWEBKIT": { |
| + "renderbuffer": "RenderbufferID" |
| + }, |
| "glFramebufferRenderbuffer": { |
| "renderbuffer": "RenderbufferID" |
| }, |
| diff --git a/scripts/generate_entry_points.py b/scripts/generate_entry_points.py |
| index 64a633840e27751dfa462074432d684072c86aef..7275f0ad674bf6977adee721c1d2f1f622850b4b 100755 |
| --- a/scripts/generate_entry_points.py |
| +++ b/scripts/generate_entry_points.py |
| @@ -1109,6 +1109,7 @@ FORMAT_DICT = { |
| "GLint": "%d", |
| "GLintptr": UNSIGNED_LONG_LONG_FORMAT, |
| "GLSETBLOBPROCANGLE": POINTER_FORMAT, |
| + "GLMTLRasterizationRateMapANGLE": POINTER_FORMAT, |
| "GLshort": "%d", |
| "GLsizei": "%d", |
| "GLsizeiptr": UNSIGNED_LONG_LONG_FORMAT, |
| diff --git a/scripts/gl_angle_ext.xml b/scripts/gl_angle_ext.xml |
| index 1c4b34c8b37a5900244e89ef6883990f0452426e..674d20d29b7c9b2b832cfb1e15ea8cd578e67a06 100644 |
| --- a/scripts/gl_angle_ext.xml |
| +++ b/scripts/gl_angle_ext.xml |
| @@ -13,6 +13,7 @@ |
| <types> |
| <type>typedef GLsizeiptr (<apientry/> *<name>GLGETBLOBPROCANGLE</name>)(const void *key, GLsizeiptr keySize, void *value, GLsizeiptr valueSize, const void *userParam);</type> |
| <type>typedef void (<apientry/> *<name>GLSETBLOBPROCANGLE</name>)(const void *key, GLsizeiptr keySize, const void *value, GLsizeiptr valueSize, const void *userParam);</type> |
| + <type>typedef void *<name>GLMTLRasterizationRateMapANGLE</name>;</type> |
| </types> |
| |
| <!-- SECTION: GL parameter class type definitions. --> |
| @@ -883,6 +884,18 @@ |
| <param len="1">void **<name>params</name></param> |
| <alias name="glGetPointerv"/> |
| </command> |
| + <command> |
| + <proto>void <name>glBindMetalRasterizationRateMapANGLE</name></proto> |
| + <param><ptype>GLuint</ptype> <name>framebuffer</name></param> |
| + <param><ptype>GLMTLRasterizationRateMapANGLE</ptype> <name>map</name></param> |
| + </command> |
| + <command> |
| + <proto>void <name>glFramebufferResolveRenderbufferWEBKIT</name></proto> |
| + <param><ptype>GLenum</ptype> <name>target</name></param> |
| + <param><ptype>GLenum</ptype> <name>attachment</name></param> |
| + <param><ptype>GLenum</ptype> <name>renderbuffertarget</name></param> |
| + <param><ptype>GLuint</ptype> <name>renderbuffer</name></param> |
| + </command> |
| </commands> |
| |
| <!-- SECTION: ANGLE extension interface definitions --> |
| @@ -1265,6 +1278,18 @@ |
| <enum name="GL_SHADER_BINARY_ANGLE"/> |
| </require> |
| </extension> |
| + <extension name="GL_ANGLE_variable_rasterization_rate_metal" supported="gles2"> |
| + <require> |
| + <enum name="GL_VARIABLE_RASTERIZATION_RATE_ANGLE"/> |
| + <enum name="GL_METAL_RASTERIZATION_RATE_MAP_BINDING_ANGLE"/> |
| + <command name="glBindMetalRasterizationRateMapANGLE"/> |
| + </require> |
| + </extension> |
| + <extension name="GL_WEBKIT_explicit_resolve_target" supported='gles2'> |
| + <require> |
| + <command name="glFramebufferResolveRenderbufferWEBKIT"/> |
| + </require> |
| + </extension> |
| <extension name="GL_ANGLE_blob_cache" supported="gles2"> |
| <require> |
| <command name="glBlobCacheCallbacksANGLE"/> |
| @@ -1467,4 +1492,8 @@ |
| <enum value="0x96EF" name="GL_BLOB_CACHE_SET_FUNCTION_ANGLE"/> |
| <enum value="0x972D" name="GL_BLOB_CACHE_USER_PARAM_ANGLE"/> |
| </enums> |
| + <enums namespace="GL" start="0x96BC" end="0x96BD" vendor="ANGLE"> |
| + <enum value="0x96BC" name="GL_VARIABLE_RASTERIZATION_RATE_ANGLE"/> |
| + <enum value="0x96BD" name="GL_METAL_RASTERIZATION_RATE_MAP_BINDING_ANGLE"/> |
| + </enums> |
| </registry> |
| diff --git a/scripts/registry_xml.py b/scripts/registry_xml.py |
| index 5e0932da552f64d9712b91891944e589f217d727..8936560ebedc9d3a872e168d2f015c2b50d2e5af 100644 |
| --- a/scripts/registry_xml.py |
| +++ b/scripts/registry_xml.py |
| @@ -69,11 +69,13 @@ angle_requestable_extensions = [ |
| "GL_ANGLE_texture_compression_dxt5", |
| "GL_ANGLE_texture_multisample", |
| "GL_ANGLE_texture_rectangle", |
| + "GL_ANGLE_variable_rasterization_rate_metal", |
| "GL_ANGLE_vulkan_image", |
| "GL_ANGLE_yuv_internal_format", |
| "GL_CHROMIUM_color_buffer_float_rgb", |
| "GL_CHROMIUM_color_buffer_float_rgba", |
| "GL_CHROMIUM_lose_context", |
| + "GL_WEBKIT_explicit_resolve_target", |
| ] |
| |
| gles_requestable_extensions = [ |
| diff --git a/scripts/run_code_generation.py b/scripts/run_code_generation.py |
| index 3ba4608e39be00612a2aa062f163bb893097be42..6e9525426564afce8e06eda325b6c7b26f5a400a 100755 |
| --- a/scripts/run_code_generation.py |
| +++ b/scripts/run_code_generation.py |
| @@ -136,7 +136,6 @@ generators = { |
| # Fast and supports --verify-only without hashes. |
| hashless_generators = { |
| 'ANGLE features': 'include/platform/gen_features.py', |
| - 'Test spec JSON': 'infra/specs/generate_test_spec_json.py', |
| } |
| |
| |
| diff --git a/src/common/PoolAlloc.cpp b/src/common/PoolAlloc.cpp |
| index ff5909fbadfeea9d77fb102ca9075e4120b916b1..9f0b594e70694e9d8c164fe41b176bc0473f60e7 100644 |
| --- a/src/common/PoolAlloc.cpp |
| +++ b/src/common/PoolAlloc.cpp |
| @@ -4,7 +4,7 @@ |
| // found in the LICENSE file. |
| // |
| // PoolAlloc.cpp: |
| -// Implements the class methods for PoolAllocator and Allocation classes. |
| +// Implements the PoolAllocator. |
| // |
| |
| #ifdef UNSAFE_BUFFERS_BUILD |
| @@ -13,16 +13,10 @@ |
| |
| #include "common/PoolAlloc.h" |
| |
| -#include <assert.h> |
| #include <stdint.h> |
| -#include <stdio.h> |
| -#include <utility> |
| |
| -#include <utility> |
| - |
| -#include "common/mathutil.h" |
| +#include "common/aligned_memory.h" |
| #include "common/platform.h" |
| -#include "common/tls.h" |
| |
| #if defined(ANGLE_WITH_ASAN) |
| # include <sanitizer/asan_interface.h> |
| @@ -30,381 +24,141 @@ |
| |
| namespace angle |
| { |
| -// If we are using guard blocks, we must track each individual allocation. If we aren't using guard |
| -// blocks, these never get instantiated, so won't have any impact. |
| |
| -class Allocation |
| -{ |
| - public: |
| - Allocation(size_t size, unsigned char *mem, Allocation *prev = 0) |
| - : mSize(size), mMem(mem), mPrevAlloc(prev) |
| - { |
| - // Allocations are bracketed: |
| - // |
| - // [allocationHeader][initialGuardBlock][userData][finalGuardBlock] |
| - // |
| - // This would be cleaner with if (kGuardBlockSize)..., but that makes the compiler print |
| - // warnings about 0 length memsets, even with the if() protecting them. |
| +// The PoolAllocator memory is aligned by starting with an aligned pointer |
| +// and reserving aligned size amount of memory. |
| +// This is, as opposed to aligning the current pointer and reserving the |
| +// exact amount. |
| +// The layout is: |
| +// [client][pad][client][pad]... |
| +// With ANGLE_POOL_ALLOC_GUARD_BLOCKS, the layout is: |
| +// [guard][client][pad/guard][guard][client][pad/guard] |
| +// ANGLE_POOL_ALLOC_GUARD_BLOCKS asserts that guards and pads are not overwritten |
| +// by the client. |
| + |
| #if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| - memset(preGuard(), kGuardBlockBeginVal, kGuardBlockSize); |
| - memset(data(), kUserDataFill, mSize); |
| - memset(postGuard(), kGuardBlockEndVal, kGuardBlockSize); |
| +constexpr uint8_t kGuardFillValue = 0xfe; |
| #endif |
| - } |
| |
| - void checkAllocList() const; |
| - |
| - static size_t AlignedHeaderSize(uint8_t *allocationBasePtr, size_t alignment) |
| +class PoolAllocator::Segment |
| +{ |
| + public: |
| + Segment() = default; |
| + explicit Segment(Span<uint8_t> data) : mData(data) {} |
| + Segment(Segment &&other) : mData(std::exchange(other.mData, {})) {} |
| + ~Segment() |
| { |
| - // Make sure that the data offset after the header is aligned to the given alignment. |
| - size_t base = reinterpret_cast<size_t>(allocationBasePtr); |
| - return rx::roundUpPow2(base + kGuardBlockSize + HeaderSize(), alignment) - base; |
| - } |
| - |
| - // Return total size needed to accommodate user buffer of 'size', |
| - // plus our tracking data and any necessary alignments. |
| - static size_t AllocationSize(uint8_t *allocationBasePtr, |
| - size_t size, |
| - size_t alignment, |
| - size_t *preAllocationPaddingOut) |
| + uint8_t *data = mData.data(); |
| + if (data != nullptr) |
| { |
| - // The allocation will be laid out as such: |
| - // |
| - // Aligned to |alignment| |
| - // ^ |
| - // preAllocationPaddingOut | |
| - // ___^___ | |
| - // / \ | |
| - // <padding>[header][guard][data][guard] |
| - // \___________ __________/ |
| - // V |
| - // dataOffset |
| - // |
| - // Note that alignment is at least as much as a pointer alignment, so the pointers in the |
| - // header are also necessarily aligned appropriately. |
| - // |
| - size_t dataOffset = AlignedHeaderSize(allocationBasePtr, alignment); |
| - *preAllocationPaddingOut = dataOffset - HeaderSize() - kGuardBlockSize; |
| - |
| - return dataOffset + size + kGuardBlockSize; |
| + size_t size = mData.size(); |
| + ANGLE_UNUSED_VARIABLE(size); |
| + ANGLE_ALLOC_PROFILE(POOL_DEALLOCATION, data, size, size > kSegmentSize); |
| + AlignedFree(data); |
| } |
| - |
| - // Given memory pointing to |header|, returns |data|. |
| - static uint8_t *GetDataPointer(uint8_t *memory, size_t alignment) |
| - { |
| - uint8_t *alignedPtr = memory + kGuardBlockSize + HeaderSize(); |
| - |
| - // |memory| must be aligned already such that user data is aligned to |alignment|. |
| - ASSERT((reinterpret_cast<uintptr_t>(alignedPtr) & (alignment - 1)) == 0); |
| - |
| - return alignedPtr; |
| } |
| - |
| - private: |
| - void checkGuardBlock(unsigned char *blockMem, unsigned char val, const char *locText) const; |
| - |
| - void checkAlloc() const |
| + Segment &operator=(Segment &&other) |
| { |
| - checkGuardBlock(preGuard(), kGuardBlockBeginVal, "before"); |
| - checkGuardBlock(postGuard(), kGuardBlockEndVal, "after"); |
| + mData = std::exchange(other.mData, {}); |
| + return *this; |
| } |
| - |
| - // Find offsets to pre and post guard blocks, and user data buffer |
| - unsigned char *preGuard() const { return mMem + HeaderSize(); } |
| - unsigned char *data() const { return preGuard() + kGuardBlockSize; } |
| - unsigned char *postGuard() const { return data() + mSize; } |
| - size_t mSize; // size of the user data area |
| - unsigned char *mMem; // beginning of our allocation (points to header) |
| - Allocation *mPrevAlloc; // prior allocation in the chain |
| - |
| - static constexpr unsigned char kGuardBlockBeginVal = 0xfb; |
| - static constexpr unsigned char kGuardBlockEndVal = 0xfe; |
| - static constexpr unsigned char kUserDataFill = 0xcd; |
| -#if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| - static constexpr size_t kGuardBlockSize = 16; |
| - static constexpr size_t HeaderSize() { return sizeof(Allocation); } |
| -#else |
| - static constexpr size_t kGuardBlockSize = 0; |
| - static constexpr size_t HeaderSize() { return 0; } |
| -#endif |
| -}; |
| - |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| -class PageHeader |
| -{ |
| - public: |
| - PageHeader(PageHeader *nextPage, size_t pageCount) |
| - : nextPage(nextPage), |
| - pageCount(pageCount) |
| + static Segment Allocate(size_t size) |
| { |
| - } |
| - |
| - PageHeader *nextPage; |
| - size_t pageCount; |
| -# if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| - Allocation *lastAllocation = nullptr; |
| -# endif |
| -}; |
| -#endif |
| - |
| -// |
| -// Implement the functionality of the PoolAllocator class, which |
| -// is documented in PoolAlloc.h. |
| -// |
| -PoolAllocator::PoolAllocator(int growthIncrement, int allocationAlignment) |
| - : |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - mPageSize(growthIncrement), |
| - mFreeList(nullptr), |
| - mInUseList(nullptr), |
| - mNumCalls(0), |
| - mTotalBytes(0), |
| -#endif |
| - mAlignment(allocationAlignment) |
| -{ |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - mPageHeaderSkip = sizeof(PageHeader); |
| - |
| - // Alignment == 1 is a special fast-path where fastAllocate() is enabled |
| - if (mAlignment != 1) |
| + ANGLE_ALLOC_PROFILE(POOL_ALLOCATION, size, size > kSegmentSize); |
| + uint8_t *result = reinterpret_cast<uint8_t *>(AlignedAlloc(size, kAlignment)); |
| + if (ANGLE_UNLIKELY(result == nullptr)) |
| { |
| -#endif |
| - // Adjust mAlignment to be at least pointer aligned and |
| - // power of 2. |
| - // |
| - size_t minAlign = sizeof(void *); |
| - if (mAlignment < minAlign) |
| - { |
| - mAlignment = minAlign; |
| + return {}; |
| } |
| - mAlignment = gl::ceilPow2(static_cast<unsigned int>(mAlignment)); |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - } |
| - // |
| - // Don't allow page sizes we know are smaller than all common |
| - // OS page sizes. |
| - // |
| - if (mPageSize < 4 * 1024) |
| - { |
| - mPageSize = 4 * 1024; |
| + return Segment{{result, size}}; |
| } |
| + uint8_t *data() const { return mData.data(); } |
| |
| - // |
| - // A large mCurrentPageOffset indicates a new page needs to |
| - // be obtained to allocate memory. |
| - // |
| - mCurrentPageOffset = mPageSize; |
| -#endif |
| -} |
| + private: |
| + Span<uint8_t> mData; |
| +}; |
| + |
| +PoolAllocator::PoolAllocator() = default; |
| |
| PoolAllocator::~PoolAllocator() |
| { |
| reset(); |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - while (mFreeList) |
| - { |
| - PageHeader *next = mFreeList->nextPage; |
| - delete[] reinterpret_cast<char *>(mFreeList); |
| - mFreeList = next; |
| - } |
| -#endif |
| } |
| |
| -// |
| -// Check a single guard block for damage |
| -// |
| -void Allocation::checkGuardBlock(unsigned char *blockMem, |
| - unsigned char val, |
| - const char *locText) const |
| -{ |
| #if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| - for (size_t x = 0; x < kGuardBlockSize; x++) |
| - { |
| - if (blockMem[x] != val) |
| - { |
| - char assertMsg[80]; |
| - // We don't print the assert message. It's here just to be helpful. |
| - snprintf(assertMsg, sizeof(assertMsg), |
| - "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n", locText, mSize, data()); |
| - assert(0 && "PoolAlloc: Damage in guard block"); |
| - } |
| - } |
| -#endif |
| + |
| +void PoolAllocator::addGuard(Span<uint8_t> guardData) |
| +{ |
| + memset(guardData.data(), kGuardFillValue, guardData.size()); |
| + mGuards.push_back(guardData); |
| } |
| |
| +#endif |
| + |
| void PoolAllocator::reset() |
| { |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - mNumCalls = 0; |
| - mTotalBytes = 0; |
| - |
| - mCurrentPageOffset = mPageSize; |
| - PageHeader *page = std::exchange(mInUseList, nullptr); |
| - while (page) |
| +#if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| + for (Span<uint8_t> guard : mGuards) |
| { |
| - const size_t pageCount = page->pageCount; |
| - PageHeader *nextInUse = page->nextPage; |
| - |
| -# if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| - if (page->lastAllocation) |
| + for (uint8_t value : guard) |
| { |
| - Allocation *allocations = std::exchange(page->lastAllocation, nullptr); |
| - allocations->checkAllocList(); |
| + ASSERT(value == kGuardFillValue); |
| } |
| -# endif |
| - |
| - if (pageCount > 1) |
| - { |
| - delete[] reinterpret_cast<uint8_t *>(page); |
| } |
| - else |
| - { |
| + mGuards.clear(); |
| +#endif |
| +#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| + mCurrentPool = {}; |
| + mUnusedSegments = std::exchange(mPoolSegments, {}); |
| # if defined(ANGLE_WITH_ASAN) |
| + for (auto &segment : mUnusedSegments) |
| + { |
| // Clear any container annotations left over from when the memory |
| // was last used. (crbug.com/1419798) |
| - __asan_unpoison_memory_region(page, mPageSize); |
| -# endif |
| - page->nextPage = mFreeList; |
| - mFreeList = page; |
| + __asan_unpoison_memory_region(segment.data(), kSegmentSize); |
| } |
| - page = nextInUse; |
| - } |
| -#else // !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - mStack.clear(); |
| +# endif |
| #endif |
| + mSingleObjectSegments.clear(); |
| } |
| |
| -void *PoolAllocator::allocate(size_t numBytes) |
| -{ |
| #if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - // |
| - // Just keep some interesting statistics. |
| - // |
| - ++mNumCalls; |
| - mTotalBytes += numBytes; |
| - |
| - uint8_t *currentPagePtr = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset; |
| - |
| - size_t preAllocationPadding = 0; |
| - size_t allocationSize = |
| - Allocation::AllocationSize(currentPagePtr, numBytes, mAlignment, &preAllocationPadding); |
| - |
| - // Integer overflow is unexpected. |
| - ASSERT(allocationSize >= numBytes); |
| |
| - // Do the allocation, most likely case first, for efficiency. |
| - if (allocationSize <= mPageSize - mCurrentPageOffset) |
| - { |
| - // There is enough room to allocate from the current page at mCurrentPageOffset. |
| - uint8_t *memory = currentPagePtr + preAllocationPadding; |
| - mCurrentPageOffset += allocationSize; |
| - |
| - return initializeAllocation(memory, numBytes); |
| - } |
| - |
| - if (allocationSize > mPageSize - mPageHeaderSkip) |
| - { |
| - // If the allocation is larger than a whole page, do a multi-page allocation. These are not |
| - // mixed with the others. The OS is efficient in allocating and freeing multiple pages. |
| - |
| - // We don't know what the alignment of the new allocated memory will be, so conservatively |
| - // allocate enough memory for up to alignment extra bytes being needed. |
| - allocationSize = Allocation::AllocationSize(reinterpret_cast<uint8_t *>(mPageHeaderSkip), |
| - numBytes, mAlignment, &preAllocationPadding); |
| - |
| - size_t numBytesToAlloc = allocationSize + mPageHeaderSkip + mAlignment; |
| - |
| - // Integer overflow is unexpected. |
| - ASSERT(numBytesToAlloc >= allocationSize); |
| - |
| - uint8_t *memory = new (std::nothrow) uint8_t[numBytesToAlloc]; |
| - if (memory == nullptr) |
| - { |
| - return nullptr; |
| - } |
| - mInUseList = |
| - new (memory) PageHeader(mInUseList, (numBytesToAlloc + mPageSize - 1) / mPageSize); |
| - |
| - // Make next allocation come from a new page |
| - mCurrentPageOffset = mPageSize; |
| - |
| - // Now that we actually have the pointer, make sure the data pointer will be aligned. |
| - currentPagePtr = reinterpret_cast<uint8_t *>(mInUseList) + mPageHeaderSkip; |
| - Allocation::AllocationSize(currentPagePtr, numBytes, mAlignment, &preAllocationPadding); |
| - |
| - return initializeAllocation(currentPagePtr + preAllocationPadding, numBytes); |
| - } |
| - |
| - uint8_t *newPageAddr = allocateNewPage(numBytes); |
| - return initializeAllocation(newPageAddr, numBytes); |
| - |
| -#else // !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - |
| - uint8_t *alloc = new (std::nothrow) uint8_t[numBytes + mAlignment - 1]; |
| - mStack.emplace_back(std::unique_ptr<uint8_t[]>(alloc)); |
| - |
| - intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc); |
| - intAlloc = rx::roundUpPow2<intptr_t>(intAlloc, mAlignment); |
| - return reinterpret_cast<void *>(intAlloc); |
| -#endif |
| -} |
| - |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| -uint8_t *PoolAllocator::allocateNewPage(size_t numBytes) |
| +bool PoolAllocator::allocateNewPoolSegment() |
| { |
| - // Need a simple page to allocate from. Pick a page from the free list, if any. Otherwise need |
| - // to make the allocation. |
| - if (mFreeList) |
| + Segment segment; |
| + if (!mUnusedSegments.empty()) |
| { |
| - PageHeader *page = mFreeList; |
| - mFreeList = mFreeList->nextPage; |
| - page->nextPage = mInUseList; |
| - mInUseList = page; |
| + segment = std::move(mUnusedSegments.back()); |
| + mUnusedSegments.pop_back(); |
| } |
| else |
| { |
| - uint8_t *memory = new (std::nothrow) uint8_t[mPageSize]; |
| - if (memory == nullptr) |
| + segment = Segment::Allocate(kSegmentSize); |
| + if (ANGLE_UNLIKELY(segment.data() == nullptr)) |
| { |
| - return nullptr; |
| + return false; |
| } |
| - mInUseList = new (memory) PageHeader(mInUseList, 1); |
| } |
| |
| - // Leave room for the page header. |
| - mCurrentPageOffset = mPageHeaderSkip; |
| - uint8_t *currentPagePtr = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset; |
| - |
| - size_t preAllocationPadding = 0; |
| - size_t allocationSize = |
| - Allocation::AllocationSize(currentPagePtr, numBytes, mAlignment, &preAllocationPadding); |
| - |
| - mCurrentPageOffset += allocationSize; |
| - |
| - // The new allocation is made after the page header and any alignment required before it. |
| - return reinterpret_cast<uint8_t *>(mInUseList) + mPageHeaderSkip + preAllocationPadding; |
| + mCurrentPool = {segment.data(), kSegmentSize}; |
| + mPoolSegments.push_back(std::move(segment)); |
| + return true; |
| } |
| |
| -void *PoolAllocator::initializeAllocation(uint8_t *memory, size_t numBytes) |
| -{ |
| -# if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| - mInUseList->lastAllocation = |
| - new (memory) Allocation(numBytes, memory, mInUseList->lastAllocation); |
| -# endif |
| - |
| - return Allocation::GetDataPointer(memory, mAlignment); |
| -} |
| #endif |
| |
| -// |
| -// Check all allocations in a list for damage by calling check on each. |
| -// |
| -void Allocation::checkAllocList() const |
| +Span<uint8_t> PoolAllocator::allocateSingleObject(size_t size) |
| { |
| - for (const Allocation *alloc = this; alloc != nullptr; alloc = alloc->mPrevAlloc) |
| + Segment segment = Segment::Allocate(size); |
| + if (ANGLE_UNLIKELY(segment.data() == nullptr)) |
| { |
| - alloc->checkAlloc(); |
| + return {}; |
| } |
| + Span<uint8_t> result{segment.data(), size}; |
| + mSingleObjectSegments.push_back(std::move(segment)); |
| + ANGLE_ALLOC_PROFILE(LOCAL_BUMP_ALLOCATION, result, true); |
| + return result; |
| } |
| |
| } // namespace angle |
| diff --git a/src/common/PoolAlloc.h b/src/common/PoolAlloc.h |
| index 016783ae32ac04437ec1b1ac152633e356dc3421..cc810ac31c5479d8d86d173df74d3ee2c00e2fb3 100644 |
| --- a/src/common/PoolAlloc.h |
| +++ b/src/common/PoolAlloc.h |
| @@ -14,7 +14,13 @@ |
| # pragma allow_unsafe_buffers |
| #endif |
| |
| -#if !defined(NDEBUG) |
| +// This include MUST precede the ANGLE_WITH_ASAN / ANGLE_WITH_TSAN check below |
| +// to define those macros. |
| +#include "common/platform.h" |
| + |
| +#if defined(ANGLE_WITH_ASAN) || defined(ANGLE_WITH_TSAN) |
| +# define ANGLE_DISABLE_POOL_ALLOC // Use system allocator under sanitizers for accurate detection |
| +#elif !defined(NDEBUG) |
| # define ANGLE_POOL_ALLOC_GUARD_BLOCKS // define to enable guard block checking |
| #endif |
| |
| @@ -37,108 +43,112 @@ |
| |
| #include <stdint.h> |
| |
| +#include <memory> |
| +#include <utility> |
| +#include <vector> |
| + |
| #include "common/angleutils.h" |
| #include "common/log_utils.h" |
| +#include "common/mathutil.h" |
| +#include "common/span.h" |
| +#ifdef ANGLE_PLATFORM_APPLE |
| +# if __has_include(<CoreFoundation/CFPriv.h>) // Matches USE_APPLE_INTERNAL_SDK in WTF. |
| +# include <WebKitAdditions/ANGLEAllocProfile.h> |
| +# endif |
| +#endif |
| |
| -#if defined(ANGLE_DISABLE_POOL_ALLOC) |
| -# include <memory> |
| -# include <vector> |
| +#if !defined(ANGLE_ALLOC_PROFILE) |
| +# define ANGLE_ALLOC_PROFILE(kind, ...) |
| +# define ANGLE_ALLOC_PROFILE_ALIGNMENT(x) (x) |
| #endif |
| |
| namespace angle |
| { |
| -class PageHeader; |
| |
| -// Pages are linked together with a simple header at the beginning |
| -// of each allocation obtained from the underlying OS. |
| -// The "page size" used is not, nor must it match, the underlying OS |
| -// page size. But, having it be about that size or equal to a set of |
| -// pages is likely most optimal. |
| -// |
| +// Allocator that allocates memory aligned to kAlignment and releases it when the instance is |
| +// destroyed. |
| class PoolAllocator : angle::NonCopyable |
| { |
| public: |
| - |
| - static const int kDefaultAlignment = sizeof(void *); |
| - // |
| - // Create PoolAllocator. If alignment is set to 1 byte then fastAllocate() |
| - // function can be used to make allocations with less overhead. |
| - // |
| - PoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = kDefaultAlignment); |
| + PoolAllocator(); |
| ~PoolAllocator(); |
| |
| + // Returns aligned pointer to 'numBytes' of memory or nullptr on allocation failure. |
| + void *allocate(size_t numBytes); |
| + |
| // Marks all allocated memory as unused. The memory will be reused. |
| void reset(); |
| |
| - // Call allocate() to actually acquire memory. Returns 0 if no memory |
| - // available, otherwise a properly aligned pointer to 'numBytes' of memory. |
| - // |
| - void *allocate(size_t numBytes); |
| + private: |
| + static constexpr size_t kAlignment = ANGLE_ALLOC_PROFILE_ALIGNMENT(sizeof(void *)); |
| + Span<uint8_t> allocateSingleObject(size_t size); |
| + class Segment; |
| + std::vector<Segment> mSingleObjectSegments; // Large objects. |
| + |
| + static constexpr size_t kSegmentSize = 32768; |
| +#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| + bool allocateNewPoolSegment(); |
| + |
| + Span<uint8_t> mCurrentPool; // The unused part of memory in last entry of mPoolSegments. |
| + std::vector<Segment> mPoolSegments; // List of currently in use memory allocations. |
| + std::vector<Segment> mUnusedSegments; // List of unused allocations after reset(). |
| +#endif |
| + |
| +#if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| + void addGuard(Span<uint8_t> guardData); |
| + |
| + std::vector<Span<uint8_t>> mGuards; // Guards, memory which is asserted to stay prestine. |
| +#endif |
| +}; |
| |
| - // |
| - // Call fastAllocate() for a faster allocate function that does minimal bookkeeping |
| - // preCondition: Allocator must have been created w/ alignment of 1 |
| - ANGLE_INLINE uint8_t *fastAllocate(size_t numBytes) |
| +inline void *PoolAllocator::allocate(size_t size) |
| +{ |
| + Span<uint8_t> data; |
| + |
| + size_t extent = size; |
| +#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| + // Allocate with kAlignment granularity to keep the next allocation aligned. |
| + extent = rx::roundUpPow2(extent, kAlignment); |
| +#endif |
| +#if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| + // Add space for guard block before. Add space for guard block after if there is no alignment |
| + // padding, else use the padding as the guard block after. |
| + extent += kAlignment + (extent == size ? kAlignment : 0); |
| +#endif |
| +#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| + if (extent <= mCurrentPool.size()) |
| + { |
| + data = mCurrentPool.first(extent); |
| + mCurrentPool = mCurrentPool.subspan(extent); |
| + ANGLE_ALLOC_PROFILE(LOCAL_BUMP_ALLOCATION, data, false); |
| + } |
| + else if (extent < kSegmentSize) |
| { |
| -#if defined(ANGLE_DISABLE_POOL_ALLOC) |
| - return reinterpret_cast<uint8_t *>(allocate(numBytes)); |
| -#else |
| - ASSERT(mAlignment == 1); |
| - // No multi-page allocations |
| - ASSERT(numBytes <= (mPageSize - mPageHeaderSkip)); |
| - // |
| - // Do the allocation, most likely case inline first, for efficiency. |
| - // |
| - if (numBytes <= mPageSize - mCurrentPageOffset) |
| + if (ANGLE_UNLIKELY(!allocateNewPoolSegment())) |
| { |
| - // |
| - // Safe to allocate from mCurrentPageOffset. |
| - // |
| - uint8_t *memory = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset; |
| - mCurrentPageOffset += numBytes; |
| - return memory; |
| + return nullptr; |
| + } |
| + data = mCurrentPool.first(extent); |
| + mCurrentPool = mCurrentPool.subspan(extent); |
| + ANGLE_ALLOC_PROFILE(LOCAL_BUMP_ALLOCATION, data, false); |
| } |
| - return allocateNewPage(numBytes); |
| + else |
| #endif |
| + { |
| + data = allocateSingleObject(extent); |
| + if (data.empty()) |
| + { |
| + return nullptr; |
| + } |
| } |
| |
| - // There is no deallocate. The point of this class is that deallocation can be skipped by the |
| - // user of it, as the model of use is to simultaneously deallocate everything at once by |
| - // destroying the instance or reset(). |
| - |
| - private: |
| -#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - // Slow path of allocation when we have to get a new page. |
| - uint8_t *allocateNewPage(size_t numBytes); |
| - // Track allocations if and only if we're using guard blocks |
| - void *initializeAllocation(uint8_t *memory, size_t numBytes); |
| - |
| - // Granularity of allocation from the OS |
| - size_t mPageSize; |
| - // Amount of memory to skip to make room for the page header (which is the size of the page |
| - // header, or PageHeader in PoolAlloc.cpp) |
| - size_t mPageHeaderSkip; |
| - // Next offset in top of inUseList to allocate from. This offset is not necessarily aligned to |
| - // anything. When an allocation is made, the data is aligned to mAlignment, and the header (if |
| - // any) will align to pointer size by extension (since mAlignment is made aligned to at least |
| - // pointer size). |
| - size_t mCurrentPageOffset; |
| - // List of unused memory. |
| - PageHeader *mFreeList; |
| - // List of all memory currently being used. The head of this list is where allocations are |
| - // currently being made from. |
| - PageHeader *mInUseList; |
| - |
| - int mNumCalls; // just an interesting statistic |
| - size_t mTotalBytes; // just an interesting statistic |
| - |
| -#else // !defined(ANGLE_DISABLE_POOL_ALLOC) |
| - std::vector<std::unique_ptr<uint8_t[]>> mStack; |
| +#if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| + addGuard(data.first(kAlignment)); |
| + data = data.subspan(kAlignment); |
| + addGuard(data.subspan(size)); |
| #endif |
| - |
| - size_t mAlignment; // all returned allocations will be aligned at |
| - // this granularity, which will be a power of 2 |
| -}; |
| + return data.first(size).data(); |
| +} |
| |
| } // namespace angle |
| |
| diff --git a/src/common/PoolAlloc_unittest.cpp b/src/common/PoolAlloc_unittest.cpp |
| index 118adbaa010da5f7437b5401b8951522b349b754..476d165676bc2d08d6f65ef7e36f6c2912f0a794 100644 |
| --- a/src/common/PoolAlloc_unittest.cpp |
| +++ b/src/common/PoolAlloc_unittest.cpp |
| @@ -17,8 +17,16 @@ |
| |
| namespace angle |
| { |
| + |
| +class PoolAllocatorTest : public testing::Test |
| +{ |
| + protected: |
| + static constexpr size_t kPoolAllocatorPageSize = 32768; |
| + static constexpr size_t kPoolAllocatorAlignment = sizeof(void *); |
| +}; |
| + |
| // Verify the public interface of PoolAllocator class |
| -TEST(PoolAllocatorTest, Interface) |
| +TEST_F(PoolAllocatorTest, Interface) |
| { |
| size_t numBytes = 1024; |
| constexpr uint32_t kTestValue = 0xbaadbeef; |
| @@ -42,42 +50,111 @@ TEST(PoolAllocatorTest, Interface) |
| // Verify first allocation still has data |
| EXPECT_EQ(kTestValue, *writePtr); |
| // Make a bunch of allocations |
| + for (uint32_t j = 0; j < 100; ++j) |
| + { |
| for (uint32_t i = 0; i < 1000; ++i) |
| { |
| - numBytes = (rand() % (1024 * 4)) + 1; |
| + numBytes = (rand() % kPoolAllocatorPageSize * 3) + 1; |
| allocation = poolAllocator.allocate(numBytes); |
| EXPECT_NE(nullptr, allocation); |
| // Write data into full allocation. In debug case if we |
| // overwrite any other allocation we get error. |
| memset(allocation, 0xb8, numBytes); |
| } |
| + poolAllocator.reset(); |
| + } |
| } |
| |
| -#if !defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| -// Verify allocations are correctly aligned for different alignments |
| -class PoolAllocatorAlignmentTest : public testing::TestWithParam<int> |
| -{}; |
| - |
| -TEST_P(PoolAllocatorAlignmentTest, Alignment) |
| +// Tests that PoolAllocator returns pointers with expected alignment. |
| +TEST_F(PoolAllocatorTest, Alignment) |
| { |
| - int alignment = GetParam(); |
| - // Create a pool allocator to allocate from |
| - PoolAllocator poolAllocator(4096, alignment); |
| - // Test a number of allocation sizes for each alignment |
| + PoolAllocator poolAllocator; |
| + for (uint32_t j = 0; j < 10; ++j) |
| + { |
| for (uint32_t i = 0; i < 100; ++i) |
| { |
| - // Vary the allocation size around 4k to hit some multi-page allocations |
| - const size_t numBytes = rand() % (1024 * 4) + 1; |
| + // Vary the allocation size to hit some large object allocations. |
| + const size_t numBytes = (rand() % kPoolAllocatorPageSize * 3) + 1; |
| void *allocation = poolAllocator.allocate(numBytes); |
| // Verify alignment of allocation matches expected default |
| - EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(allocation) % alignment) |
| - << "Iteration " << i << " allocating " << numBytes; |
| + EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(allocation) % kPoolAllocatorAlignment) |
| + << "Iteration " << j << ", " << i << " allocating " << numBytes |
| + << " got: " << allocation; |
| + memset(allocation, i, numBytes); |
| + } |
| + poolAllocator.reset(); |
| } |
| } |
| |
| -INSTANTIATE_TEST_SUITE_P(, |
| - PoolAllocatorAlignmentTest, |
| - testing::Values(2, 4, 8, 16, 32, 64, 128), |
| - testing::PrintToStringParamName()); |
| +#if !defined(ANGLE_DISABLE_POOL_ALLOC) |
| + |
| +// Test that reset recycles memory. |
| +TEST_F(PoolAllocatorTest, ResetRecyclesMemory) |
| +{ |
| + PoolAllocator poolAllocator; |
| + void *allocation1 = poolAllocator.allocate(1); |
| + void *allocation2 = poolAllocator.allocate(2); |
| + memset(allocation1, 11, 1); |
| + memset(allocation2, 12, 2); |
| + ANGLE_ALLOC_PROFILE(POINTER, allocation1); |
| + ANGLE_ALLOC_PROFILE(POINTER, allocation2); |
| + poolAllocator.reset(); |
| + void *allocation3 = poolAllocator.allocate(1); |
| + void *allocation4 = poolAllocator.allocate(2); |
| + memset(allocation3, 21, 1); |
| + memset(allocation4, 22, 2); |
| + ANGLE_ALLOC_PROFILE(POINTER, allocation3); |
| + ANGLE_ALLOC_PROFILE(POINTER, allocation4); |
| + EXPECT_NE(allocation1, nullptr); |
| + EXPECT_NE(allocation2, nullptr); |
| + EXPECT_NE(allocation1, allocation2); |
| + EXPECT_EQ(allocation1, allocation3); |
| + EXPECT_EQ(allocation2, allocation4); |
| +} |
| + |
| #endif |
| + |
| +#if defined(ANGLE_POOL_ALLOC_GUARD_BLOCKS) |
| + |
| +class PoolAllocatorGuardTest : public PoolAllocatorTest |
| +{}; |
| + |
| +#ifdef GTEST_HAS_DEATH_TEST |
| +// Verify that alignment guard detects overflowing write. |
| +TEST_F(PoolAllocatorGuardTest, AlignmentGuardDetectsOverflowWrite) |
| +{ |
| + auto testOverflowAlignment = []() { |
| + PoolAllocator poolAllocator; |
| + void *allocation = poolAllocator.allocate(15); |
| + memset(allocation, 11, 16); |
| + }; |
| + ASSERT_DEATH(testOverflowAlignment(), ""); |
| +} |
| + |
| +// Verify that allocation guard detects overflowing write. |
| +TEST_F(PoolAllocatorGuardTest, AllocationGuardsDetectsOverflowWrite) |
| +{ |
| + auto testOverflow = []() { |
| + PoolAllocator poolAllocator; |
| + void *allocation1 = poolAllocator.allocate(16); |
| + memset(allocation1, 11, 17); |
| + }; |
| + ASSERT_DEATH(testOverflow(), ""); |
| +} |
| + |
| +// Verify that allocation guard detects underflowing write. |
| +TEST_F(PoolAllocatorGuardTest, AllocationGuardsDetectsUnderflowWrite) |
| +{ |
| + auto testUnderflow = []() { |
| + PoolAllocator poolAllocator; |
| + void *allocation1 = poolAllocator.allocate(16); |
| + memset(reinterpret_cast<uint8_t *>(allocation1) - 1, 11, 1); |
| + }; |
| + ASSERT_DEATH(testUnderflow(), ""); |
| +} |
| + |
| +#endif |
| + |
| +#endif |
| + |
| } // namespace angle |
| diff --git a/src/common/angleutils.h b/src/common/angleutils.h |
| index 2a8ca19f2ffab3c0eff5991663b0d873a3d05474..ef289d786758a2fcf916f349f0c8317f63b25fe3 100644 |
| --- a/src/common/angleutils.h |
| +++ b/src/common/angleutils.h |
| @@ -436,6 +436,13 @@ inline bool IsLittleEndian() |
| UNREACHABLE(); \ |
| ANGLE_CHECK(context, false, "Unreachable code.", GL_INVALID_OPERATION) |
| |
| +#define ANGLE_CHECK_ASSERT(context, result) \ |
| + do { \ |
| + bool resultValue = (result); \ |
| + ASSERT(resultValue); \ |
| + ANGLE_CHECK(context, resultValue, gl::err::kInternalError, GL_INVALID_OPERATION); \ |
| + } while (false) |
| + |
| #if defined(ANGLE_WITH_LSAN) |
| # define ANGLE_SCOPED_DISABLE_LSAN() __lsan::ScopedDisabler lsanDisabler |
| #else |
| diff --git a/src/common/debug.cpp b/src/common/debug.cpp |
| index be8f721b0e9c50217e8216fe8341584f3671fc43..20501c290144dc73ed3c5f1d882a001fe1d41804 100644 |
| --- a/src/common/debug.cpp |
| +++ b/src/common/debug.cpp |
| @@ -43,6 +43,14 @@ |
| #include "common/entry_points_enum_autogen.h" |
| #include "common/system_utils.h" |
| |
| +#if defined(ANGLE_ENABLE_ASSERTS) |
| +bool AreAssertionsEnabled() |
| +{ |
| + static bool enabled = [] { return angle::GetEnvironmentVar("ANGLE_DISABLE_ASSERTS") != "1"; }(); |
| + return enabled; |
| +} |
| +#endif // defined(ANGLE_ENABLE_ASSERTS) |
| + |
| namespace gl |
| { |
| |
| diff --git a/src/common/debug.h b/src/common/debug.h |
| index 48a1979e5edb3165d659c000c789f9a705809923..0ae642f624bca7ae94c595327058fb76bb6c8e50 100644 |
| --- a/src/common/debug.h |
| +++ b/src/common/debug.h |
| @@ -177,4 +177,15 @@ angle::SimpleMutex &GetDebugMutex(); |
| # define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING |
| #endif |
| |
| +// clang-format off |
| +#if defined(__clang__) |
| +# define ANGLE_DISABLE_NONLITERAL_FORMAT_WARNING \ |
| + _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"") |
| +# define ANGLE_REENABLE_NONLITERAL_FORMAT_WARNING _Pragma("clang diagnostic pop") |
| +#else |
| +# define ANGLE_DISABLE_NONLITERAL_FORMAT_WARNING |
| +# define ANGLE_REENABLE_NONLITERAL_FORMAT_WARNING |
| +#endif |
| +// clang-format on |
| + |
| #endif // COMMON_DEBUG_H_ |
| diff --git a/src/common/entry_points_enum_autogen.cpp b/src/common/entry_points_enum_autogen.cpp |
| index 28b10976bfe08d8cf2fece6343179c387ef72b4e..14e41ff7307e12a86270e856feb26b2688d57a7a 100644 |
| --- a/src/common/entry_points_enum_autogen.cpp |
| +++ b/src/common/entry_points_enum_autogen.cpp |
| @@ -534,6 +534,8 @@ const char *GetEntryPointName(EntryPoint ep) |
| return "glBindFramebufferOES"; |
| case EntryPoint::GLBindImageTexture: |
| return "glBindImageTexture"; |
| + case EntryPoint::GLBindMetalRasterizationRateMapANGLE: |
| + return "glBindMetalRasterizationRateMapANGLE"; |
| case EntryPoint::GLBindProgramPipeline: |
| return "glBindProgramPipeline"; |
| case EntryPoint::GLBindProgramPipelineEXT: |
| @@ -954,6 +956,8 @@ const char *GetEntryPointName(EntryPoint ep) |
| return "glFramebufferRenderbuffer"; |
| case EntryPoint::GLFramebufferRenderbufferOES: |
| return "glFramebufferRenderbufferOES"; |
| + case EntryPoint::GLFramebufferResolveRenderbufferWEBKIT: |
| + return "glFramebufferResolveRenderbufferWEBKIT"; |
| case EntryPoint::GLFramebufferShadingRateEXT: |
| return "glFramebufferShadingRateEXT"; |
| case EntryPoint::GLFramebufferTexture: |
| diff --git a/src/common/entry_points_enum_autogen.h b/src/common/entry_points_enum_autogen.h |
| index a8709541146086f6798b5d8cb55ed6d1be08ca38..ddec3494a8bd72115117f8372a1cb0446ee4ae91 100644 |
| --- a/src/common/entry_points_enum_autogen.h |
| +++ b/src/common/entry_points_enum_autogen.h |
| @@ -273,6 +273,7 @@ enum class EntryPoint |
| GLBindFramebuffer, |
| GLBindFramebufferOES, |
| GLBindImageTexture, |
| + GLBindMetalRasterizationRateMapANGLE, |
| GLBindProgramPipeline, |
| GLBindProgramPipelineEXT, |
| GLBindRenderbuffer, |
| @@ -483,6 +484,7 @@ enum class EntryPoint |
| GLFramebufferPixelLocalStorageRestoreANGLE, |
| GLFramebufferRenderbuffer, |
| GLFramebufferRenderbufferOES, |
| + GLFramebufferResolveRenderbufferWEBKIT, |
| GLFramebufferShadingRateEXT, |
| GLFramebufferTexture, |
| GLFramebufferTexture2D, |
| diff --git a/src/common/frame_capture_utils_autogen.cpp b/src/common/frame_capture_utils_autogen.cpp |
| index 187ed9deb3afc249749de329f2103ff653094a6f..822ffccf72250a84c7ab4a62886b58d68583797a 100644 |
| --- a/src/common/frame_capture_utils_autogen.cpp |
| +++ b/src/common/frame_capture_utils_autogen.cpp |
| @@ -228,6 +228,10 @@ void WriteParamCaptureReplay(std::ostream &os, const CallCapture &call, const Pa |
| WriteParamValueReplay<ParamType::TGLGETBLOBPROCANGLE>( |
| os, call, param.value.GLGETBLOBPROCANGLEVal); |
| break; |
| + case ParamType::TGLMTLRasterizationRateMapANGLE: |
| + WriteParamValueReplay<ParamType::TGLMTLRasterizationRateMapANGLE>( |
| + os, call, param.value.GLMTLRasterizationRateMapANGLEVal); |
| + break; |
| case ParamType::TGLSETBLOBPROCANGLE: |
| WriteParamValueReplay<ParamType::TGLSETBLOBPROCANGLE>( |
| os, call, param.value.GLSETBLOBPROCANGLEVal); |
| @@ -1044,6 +1048,8 @@ const char *ParamTypeToString(ParamType paramType) |
| return "GLDEBUGPROCKHR"; |
| case ParamType::TGLGETBLOBPROCANGLE: |
| return "GLGETBLOBPROCANGLE"; |
| + case ParamType::TGLMTLRasterizationRateMapANGLE: |
| + return "GLMTLRasterizationRateMapANGLE"; |
| case ParamType::TGLSETBLOBPROCANGLE: |
| return "GLSETBLOBPROCANGLE"; |
| case ParamType::TGLbitfield: |
| diff --git a/src/common/frame_capture_utils_autogen.h b/src/common/frame_capture_utils_autogen.h |
| index f0ee62ddeb5c321a4e53e046e0769c83b6d3eb29..3ba968732aaeb92939d2ad16159600ee51f71c01 100644 |
| --- a/src/common/frame_capture_utils_autogen.h |
| +++ b/src/common/frame_capture_utils_autogen.h |
| @@ -102,6 +102,7 @@ enum class ParamType |
| TGLDEBUGPROC, |
| TGLDEBUGPROCKHR, |
| TGLGETBLOBPROCANGLE, |
| + TGLMTLRasterizationRateMapANGLE, |
| TGLSETBLOBPROCANGLE, |
| TGLbitfield, |
| TGLboolean, |
| @@ -283,7 +284,7 @@ enum class ParamType |
| TvoidPointerPointer, |
| }; |
| |
| -constexpr uint32_t kParamTypeCount = 246; |
| +constexpr uint32_t kParamTypeCount = 247; |
| |
| union ParamValue |
| { |
| @@ -348,6 +349,7 @@ union ParamValue |
| GLDEBUGPROC GLDEBUGPROCVal; |
| GLDEBUGPROCKHR GLDEBUGPROCKHRVal; |
| GLGETBLOBPROCANGLE GLGETBLOBPROCANGLEVal; |
| + GLMTLRasterizationRateMapANGLE GLMTLRasterizationRateMapANGLEVal; |
| GLSETBLOBPROCANGLE GLSETBLOBPROCANGLEVal; |
| GLbitfield GLbitfieldVal; |
| GLboolean GLbooleanVal; |
| @@ -928,6 +930,14 @@ inline GLGETBLOBPROCANGLE GetParamVal<ParamType::TGLGETBLOBPROCANGLE, GLGETBLOBP |
| return value.GLGETBLOBPROCANGLEVal; |
| } |
| |
| +template <> |
| +inline GLMTLRasterizationRateMapANGLE |
| +GetParamVal<ParamType::TGLMTLRasterizationRateMapANGLE, GLMTLRasterizationRateMapANGLE>( |
| + const ParamValue &value) |
| +{ |
| + return value.GLMTLRasterizationRateMapANGLEVal; |
| +} |
| + |
| template <> |
| inline GLSETBLOBPROCANGLE GetParamVal<ParamType::TGLSETBLOBPROCANGLE, GLSETBLOBPROCANGLE>( |
| const ParamValue &value) |
| @@ -2323,6 +2333,8 @@ T AccessParamValue(ParamType paramType, const ParamValue &value) |
| return GetParamVal<ParamType::TGLDEBUGPROCKHR, T>(value); |
| case ParamType::TGLGETBLOBPROCANGLE: |
| return GetParamVal<ParamType::TGLGETBLOBPROCANGLE, T>(value); |
| + case ParamType::TGLMTLRasterizationRateMapANGLE: |
| + return GetParamVal<ParamType::TGLMTLRasterizationRateMapANGLE, T>(value); |
| case ParamType::TGLSETBLOBPROCANGLE: |
| return GetParamVal<ParamType::TGLSETBLOBPROCANGLE, T>(value); |
| case ParamType::TGLbitfield: |
| @@ -3061,6 +3073,14 @@ inline void SetParamVal<ParamType::TGLGETBLOBPROCANGLE>(GLGETBLOBPROCANGLE value |
| valueOut->GLGETBLOBPROCANGLEVal = valueIn; |
| } |
| |
| +template <> |
| +inline void SetParamVal<ParamType::TGLMTLRasterizationRateMapANGLE>( |
| + GLMTLRasterizationRateMapANGLE valueIn, |
| + ParamValue *valueOut) |
| +{ |
| + valueOut->GLMTLRasterizationRateMapANGLEVal = valueIn; |
| +} |
| + |
| template <> |
| inline void SetParamVal<ParamType::TGLSETBLOBPROCANGLE>(GLSETBLOBPROCANGLE valueIn, |
| ParamValue *valueOut) |
| @@ -4496,6 +4516,9 @@ void InitParamValue(ParamType paramType, T valueIn, ParamValue *valueOut) |
| case ParamType::TGLGETBLOBPROCANGLE: |
| SetParamVal<ParamType::TGLGETBLOBPROCANGLE>(valueIn, valueOut); |
| break; |
| + case ParamType::TGLMTLRasterizationRateMapANGLE: |
| + SetParamVal<ParamType::TGLMTLRasterizationRateMapANGLE>(valueIn, valueOut); |
| + break; |
| case ParamType::TGLSETBLOBPROCANGLE: |
| SetParamVal<ParamType::TGLSETBLOBPROCANGLE>(valueIn, valueOut); |
| break; |
| diff --git a/src/common/gl_enum_utils_autogen.cpp b/src/common/gl_enum_utils_autogen.cpp |
| index 27b44ad85f04e6108400f4b8a97f63ff78c5f41f..b56072ca70f68e41f2b43ea38f40fbfebf3e8aa3 100644 |
| --- a/src/common/gl_enum_utils_autogen.cpp |
| +++ b/src/common/gl_enum_utils_autogen.cpp |
| @@ -2812,6 +2812,10 @@ const char *GLenumToString(GLESEnum enumGroup, unsigned int value) |
| return "GL_RGBX8_ANGLE"; |
| case 0x96BB: |
| return "GL_SHADER_BINARY_ANGLE"; |
| + case 0x96BC: |
| + return "GL_VARIABLE_RASTERIZATION_RATE_ANGLE"; |
| + case 0x96BD: |
| + return "GL_METAL_RASTERIZATION_RATE_MAP_BINDING_ANGLE"; |
| case 0x96BE: |
| return "GL_PROGRAM_BINARY_READY_ANGLE"; |
| case 0x96C0: |
| @@ -11840,6 +11844,7 @@ static StringEnumEntry g_stringEnumTable[] = { |
| {"GL_MESH_VERTICES_OUT_NV", 0x9579}, |
| {"GL_MESH_WORK_GROUP_SIZE_EXT", 0x953E}, |
| {"GL_MESH_WORK_GROUP_SIZE_NV", 0x953E}, |
| + {"GL_METAL_RASTERIZATION_RATE_MAP_BINDING_ANGLE", 0x96BD}, |
| {"GL_MIN", 0x8007}, |
| {"GL_MINMAX", 0x802E}, |
| {"GL_MINMAX_EXT", 0x802E}, |
| @@ -14542,6 +14547,7 @@ static StringEnumEntry g_stringEnumTable[] = { |
| {"GL_VARIABLE_E_NV", 0x8527}, |
| {"GL_VARIABLE_F_NV", 0x8528}, |
| {"GL_VARIABLE_G_NV", 0x8529}, |
| + {"GL_VARIABLE_RASTERIZATION_RATE_ANGLE", 0x96BC}, |
| {"GL_VARIANT_ARRAY_EXT", 0x87E8}, |
| {"GL_VARIANT_ARRAY_POINTER_EXT", 0x87E9}, |
| {"GL_VARIANT_ARRAY_STRIDE_EXT", 0x87E6}, |
| diff --git a/src/common/log_utils.h b/src/common/log_utils.h |
| index 9034ba9fa2f68d830a2d3c3c2b72626832602ef9..7abf8d6518587af2b84581815afcc71ce75ca1af 100644 |
| --- a/src/common/log_utils.h |
| +++ b/src/common/log_utils.h |
| @@ -262,10 +262,13 @@ std::ostream &FmtHex(std::ostream &os, T value) |
| |
| // A macro asserting a condition and outputting failures to the debug log |
| #if defined(ANGLE_ENABLE_ASSERTS) |
| +bool AreAssertionsEnabled(); |
| # define ASSERT(expression) \ |
| (expression ? static_cast<void>(0) \ |
| - : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \ |
| - << ":" << __LINE__ << "): " << #expression)) |
| + : (!AreAssertionsEnabled() \ |
| + ? static_cast<void>(0) \ |
| + : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" \ |
| + << __FILE__ << ":" << __LINE__ << "): " << #expression))) |
| #else |
| # define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition) |
| #endif // defined(ANGLE_ENABLE_ASSERTS) |
| diff --git a/src/common/mathutil.h b/src/common/mathutil.h |
| index 7092d00683bc6ed51d7510a4db82b985534c35af..3543228707e1f0edcf906b76bf8d93177ee41830 100644 |
| --- a/src/common/mathutil.h |
| +++ b/src/common/mathutil.h |
| @@ -872,12 +872,8 @@ struct IndexRange |
| {}; |
| IndexRange(Undefined) {} |
| IndexRange() = default; |
| - IndexRange(uint32_t start, uint32_t end) |
| - : mStart(start), mEnd(end), mCount(static_cast<uint64_t>(end - start) + 1) |
| - { |
| - ASSERT(start <= end); |
| - } |
| - bool isEmpty() const { return mCount == 0; } |
| + IndexRange(uint32_t start, uint32_t end) : mStart(start), mEnd(end) { ASSERT(mStart <= mEnd); } |
| + bool isEmpty() const { return mStart > mEnd; } |
| uint32_t start() const |
| { |
| ASSERT(!isEmpty()); |
| @@ -890,22 +886,20 @@ struct IndexRange |
| } |
| |
| // Number of vertices in the range. |
| - uint64_t vertexCount() const { return mCount; } |
| + // Range: [0, 0] == 1 |
| + // Range: [0, 0xFFFFFFFF] == 0x100000000 (needs size_t). |
| + size_t vertexCount() const |
| + { |
| + // Note: unsigned underflow ok on isEmpty() == true. |
| + return static_cast<size_t>(mEnd) - mStart + 1u; |
| + } |
| |
| private: |
| - uint32_t mStart{0}; |
| + uint32_t mStart{1}; |
| uint32_t mEnd{0}; |
| - |
| - // Since the range is inclusive, mCount == 0 indicates an empty range |
| - uint64_t mCount{0}; |
| + friend bool operator==(const IndexRange &a, const IndexRange &b) noexcept = default; |
| }; |
| |
| -inline bool operator==(const IndexRange &a, const IndexRange &b) |
| -{ |
| - return a.vertexCount() == b.vertexCount() && |
| - ((a.vertexCount() == 0) || (a.start() == b.start())); |
| -} |
| - |
| std::ostream &operator<<(std::ostream &s, const IndexRange &a); |
| |
| // Combine a floating-point value representing a mantissa (x) and an integer exponent (exp) into a |
| diff --git a/src/common/platform_helpers.h b/src/common/platform_helpers.h |
| index d078be136529341add6a7c50ec306b5f6997d18a..f6bc86e775e32b4fd99dc40bd87360028f2a3749 100644 |
| --- a/src/common/platform_helpers.h |
| +++ b/src/common/platform_helpers.h |
| @@ -60,6 +60,15 @@ inline constexpr bool IsIOS() |
| #endif |
| } |
| |
| +inline constexpr bool IsIOSSimulator() |
| +{ |
| +#if defined(ANGLE_PLATFORM_IOS_FAMILY_SIMULATOR) |
| + return true; |
| +#else |
| + return false; |
| +#endif |
| +} |
| + |
| inline constexpr bool IsLinux() |
| { |
| #if defined(ANGLE_PLATFORM_LINUX) |
| diff --git a/src/common/tls.cpp b/src/common/tls.cpp |
| index 9600bae1a49fc9b6c409dfe311439a630b3b29f2..b66a225f407cc74f50e0be4015692a8cd94dffd0 100644 |
| --- a/src/common/tls.cpp |
| +++ b/src/common/tls.cpp |
| @@ -20,7 +20,6 @@ |
| # include <wrl/async.h> |
| # include <wrl/client.h> |
| |
| -using namespace std; |
| using namespace Windows::Foundation; |
| using namespace ABI::Windows::System::Threading; |
| |
| diff --git a/src/common/utilities.cpp b/src/common/utilities.cpp |
| index d1dc4c68fb11501d51917e797d04d79dd8618d10..d618ffdda8d2fcc02067b79a89452180b42915fe 100644 |
| --- a/src/common/utilities.cpp |
| +++ b/src/common/utilities.cpp |
| @@ -10,6 +10,12 @@ |
| |
| // utilities.cpp: Conversion functions and other utility routines. |
| |
| +// Older clang versions have a false positive on this warning here. |
| +// TODO(dino): Is this still necessary? |
| +#if defined(__clang__) |
| +# pragma clang diagnostic ignored "-Wglobal-constructors" |
| +#endif |
| + |
| #include "common/utilities.h" |
| #include "GLES3/gl3.h" |
| #include "common/mathutil.h" |
| diff --git a/src/common/utilities.h b/src/common/utilities.h |
| index c940e6a01a531eb9cd0489dac28ea992d017fb82..aa7ceb58ddbfcf65222a6445b737bd9abd0860de 100644 |
| --- a/src/common/utilities.h |
| +++ b/src/common/utilities.h |
| @@ -101,9 +101,9 @@ constexpr T GetPrimitiveRestartIndexFromType() |
| static_assert(GetPrimitiveRestartIndexFromType<uint8_t>() == 0xFF, |
| "verify restart index for uint8_t values"); |
| static_assert(GetPrimitiveRestartIndexFromType<uint16_t>() == 0xFFFF, |
| - "verify restart index for uint8_t values"); |
| + "verify restart index for uint16_t values"); |
| static_assert(GetPrimitiveRestartIndexFromType<uint32_t>() == 0xFFFFFFFF, |
| - "verify restart index for uint8_t values"); |
| + "verify restart index for uint32_t values"); |
| |
| bool IsTriangleMode(PrimitiveMode drawMode); |
| bool IsPolygonMode(PrimitiveMode mode); |
| diff --git a/src/common/utilities_unittest.cpp b/src/common/utilities_unittest.cpp |
| index 119e4c52d755b640e693da8e294313bd9ed42395..8c65c08e9e3da8ad9e356fa0de38b0ea6af43995 100644 |
| --- a/src/common/utilities_unittest.cpp |
| +++ b/src/common/utilities_unittest.cpp |
| @@ -256,6 +256,34 @@ TEST(Utilities, IndexRanges) |
| EXPECT_EQ(ComputeIndexRange(b, vertices2, 2, false), gl::IndexRange(255, 255)); |
| EXPECT_EQ(ComputeIndexRange(b, vertices2, 3, true), gl::IndexRange(2, 2)); |
| EXPECT_EQ(ComputeIndexRange(b, vertices2, 3, false), gl::IndexRange(2, 255)); |
| + |
| + constexpr auto i = gl::DrawElementsType::UnsignedInt; |
| + uint32_t vertices3[] = { |
| + 0, |
| + 0xff, |
| + 0xffffffff, |
| + }; |
| + EXPECT_EQ(ComputeIndexRange(i, vertices3, 1, true), gl::IndexRange(0, 0)); |
| + EXPECT_EQ(ComputeIndexRange(i, vertices3, 2, true), gl::IndexRange(0, 255)); |
| + EXPECT_EQ(ComputeIndexRange(i, vertices3, 2, false), gl::IndexRange(0, 255)); |
| + EXPECT_EQ(ComputeIndexRange(i, vertices3, 3, true), gl::IndexRange(0, 255)); |
| + EXPECT_EQ(ComputeIndexRange(i, vertices3, 3, false), gl::IndexRange(0, 0xffffffff)); |
| + EXPECT_EQ(ComputeIndexRange(i, vertices3 + 1, 2, true), gl::IndexRange(255, 255)); |
| + EXPECT_EQ(ComputeIndexRange(i, vertices3 + 1, 2, false), gl::IndexRange(255, 0xffffffff)); |
| + |
| + EXPECT_TRUE(gl::IndexRange().isEmpty()); |
| + EXPECT_FALSE(gl::IndexRange(0, 0).isEmpty()); |
| + EXPECT_FALSE(gl::IndexRange(0xfffffffe, 0xffffffff).isEmpty()); |
| + EXPECT_FALSE(gl::IndexRange(0xffffffff, 0xffffffff).isEmpty()); |
| + |
| + EXPECT_EQ(0u, gl::IndexRange().vertexCount()); |
| + EXPECT_EQ(1u, gl::IndexRange(0, 0).vertexCount()); |
| + EXPECT_EQ(1u, gl::IndexRange(255, 255).vertexCount()); |
| + EXPECT_EQ(255u, gl::IndexRange(1, 255).vertexCount()); |
| + EXPECT_EQ(256u, gl::IndexRange(0, 255).vertexCount()); |
| + |
| + EXPECT_EQ(0xffffffffu, gl::IndexRange(1, 0xffffffff).vertexCount()); |
| + EXPECT_EQ(static_cast<size_t>(0x100000000ull), gl::IndexRange(0, 0xffffffff).vertexCount()); |
| } |
| |
| } // anonymous namespace |
| diff --git a/src/compiler/fuzz/translator_fuzzer.cpp b/src/compiler/fuzz/translator_fuzzer.cpp |
| index fe1296f79d8bc95a64bd6348257578e7963cc7f1..465a9581585bf7491d5531504fadece65342fcc0 100644 |
| --- a/src/compiler/fuzz/translator_fuzzer.cpp |
| +++ b/src/compiler/fuzz/translator_fuzzer.cpp |
| @@ -160,6 +160,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
| } |
| |
| std::vector<uint32_t> validOutputs; |
| +#ifndef ANGLE_TRANSLATOR_FUZZER_METAL_ONLY |
| validOutputs.push_back(SH_ESSL_OUTPUT); |
| validOutputs.push_back(SH_GLSL_150_CORE_OUTPUT); |
| validOutputs.push_back(SH_GLSL_330_CORE_OUTPUT); |
| @@ -172,6 +173,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
| validOutputs.push_back(SH_SPIRV_VULKAN_OUTPUT); |
| validOutputs.push_back(SH_HLSL_3_0_OUTPUT); |
| validOutputs.push_back(SH_HLSL_4_1_OUTPUT); |
| +#endif |
| +#ifdef ANGLE_ENABLE_METAL |
| + validOutputs.push_back(SH_MSL_METAL_OUTPUT); |
| +#endif |
| bool found = false; |
| for (auto valid : validOutputs) |
| { |
| @@ -203,6 +208,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
| |
| if (translator == nullptr) |
| { |
| + sh::Finalize(); |
| return 0; |
| } |
| |
| @@ -236,6 +242,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
| |
| if (!translator->Init(resources)) |
| { |
| + sh::Finalize(); |
| return 0; |
| } |
| |
| @@ -271,5 +278,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
| |
| translator->compile(shaderStrings, options); |
| |
| + sh::Finalize(); |
| return 0; |
| } |
| diff --git a/src/compiler/generate_parser_tools.py b/src/compiler/generate_parser_tools.py |
| index 71b370065e00ed5cb20738f977ac0243d2c9c4c6..3422ace60c834f8b3064a5251886e80965444e31 100644 |
| --- a/src/compiler/generate_parser_tools.py |
| +++ b/src/compiler/generate_parser_tools.py |
| @@ -16,6 +16,10 @@ is_linux = platform.system() == 'Linux' |
| is_mac = platform.system() == 'Darwin' |
| is_windows = platform.system() == 'Windows' |
| |
| +license_note = """/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of |
| + * the BSD license. */ |
| + |
| +""" |
| |
| def get_tool_path_platform(tool_name, platform): |
| exe_path = os.path.join(sys.path[0], '..', '..', '..', 'tools', 'flex-bison', platform) |
| @@ -122,6 +126,15 @@ def run_bison(basename, generate_header): |
| |
| process = subprocess.Popen(bison_args, env=bison_env, cwd=sys.path[0]) |
| process.communicate() |
| + |
| + for fn in [output_source] + ([output_header] if generate_header else []): |
| + with open(fn, 'r') as output_file: |
| + text = output_file.read() |
| + |
| + with open(fn, 'w') as output_file: |
| + output_file.write(license_note) |
| + output_file.write(text) |
| + |
| return process.returncode |
| |
| |
| diff --git a/src/compiler/preprocessor/preprocessor.l b/src/compiler/preprocessor/preprocessor.l |
| index fac90fe40507660826bbe081f3ab47f2968be0fa..863059217a9ce883437074bbe06dc7738df4e5ce 100644 |
| --- a/src/compiler/preprocessor/preprocessor.l |
| +++ b/src/compiler/preprocessor/preprocessor.l |
| @@ -26,6 +26,11 @@ IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN scripts/run_code_generation.py |
| #ifdef UNSAFE_BUFFERS_BUILD |
| #pragma allow_unsafe_buffers |
| #endif |
| + |
| +// Rename yyalloc/yyrealloc/yyfree during flex generation to allow macro definitions. |
| +#define yyalloc yyalloc_FLEXGEN |
| +#define yyrealloc yyrealloc_FLEXGEN |
| +#define yyfree yyfree_FLEXGEN |
| } |
| |
| %{ |
| @@ -98,8 +103,17 @@ typedef angle::pp::SourceLocation YYLTYPE; |
| #define YY_INPUT(buf, result, maxSize) \ |
| result = yyextra->input.read(buf, maxSize, &yylineno); |
| |
| +// Undefine renames and define yyalloc/yyrealloc/yyfree as macros for typed malloc support. |
| +#undef yyalloc |
| +#undef yyrealloc |
| +#undef yyfree |
| +#define yyalloc(size, yyscanner) malloc(size) |
| +#define yyrealloc(ptr, size, yyscanner) realloc((ptr), (size)) |
| +#define yyfree(ptr, yyscanner) free(ptr) |
| + |
| %} |
| |
| +%option noyyalloc noyyrealloc noyyfree |
| %option noyywrap nounput never-interactive |
| %option reentrant bison-bridge bison-locations |
| %option prefix="pp" |
| diff --git a/src/compiler/preprocessor/preprocessor_lex_autogen.cpp b/src/compiler/preprocessor/preprocessor_lex_autogen.cpp |
| index e7bfcd5679221d5899ab8f107231631de8c97c1b..cd96d894165cdd2b8935fa771da3b33bb2243a2c 100644 |
| --- a/src/compiler/preprocessor/preprocessor_lex_autogen.cpp |
| +++ b/src/compiler/preprocessor/preprocessor_lex_autogen.cpp |
| @@ -13,6 +13,11 @@ |
| # pragma allow_unsafe_buffers |
| #endif |
| |
| +// Rename yyalloc/yyrealloc/yyfree during flex generation to allow macro definitions. |
| +#define yyalloc yyalloc_FLEXGEN |
| +#define yyrealloc yyrealloc_FLEXGEN |
| +#define yyfree yyfree_FLEXGEN |
| + |
| #define YY_INT_ALIGNED short int |
| |
| /* A lexical scanner generated by flex */ |
| @@ -758,6 +763,14 @@ typedef angle::pp::SourceLocation YYLTYPE; |
| |
| #define YY_INPUT(buf, result, maxSize) result = yyextra->input.read(buf, maxSize, &yylineno); |
| |
| +// Undefine renames and define yyalloc/yyrealloc/yyfree as macros for typed malloc support. |
| +#undef yyalloc |
| +#undef yyrealloc |
| +#undef yyfree |
| +#define yyalloc(size, yyscanner) malloc(size) |
| +#define yyrealloc(ptr, size, yyscanner) realloc((ptr), (size)) |
| +#define yyfree(ptr, yyscanner) free(ptr) |
| + |
| #define INITIAL 0 |
| #define COMMENT 1 |
| |
| @@ -2596,35 +2609,6 @@ static int yy_flex_strlen(const char *s, yyscan_t yyscanner) |
| } |
| #endif |
| |
| -void *yyalloc(yy_size_t size, yyscan_t yyscanner) |
| -{ |
| - struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; |
| - (void)yyg; |
| - return malloc(size); |
| -} |
| - |
| -void *yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner) |
| -{ |
| - struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; |
| - (void)yyg; |
| - |
| - /* The cast to (char *) in the following accommodates both |
| - * implementations that use char* generic pointers, and those |
| - * that use void* generic pointers. It works with the latter |
| - * because both ANSI C and C++ allow castless assignment from |
| - * any pointer type to void*, and deal with argument conversions |
| - * as though doing an assignment. |
| - */ |
| - return realloc(ptr, size); |
| -} |
| - |
| -void yyfree(void *ptr, yyscan_t yyscanner) |
| -{ |
| - struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; |
| - (void)yyg; |
| - free((char *)ptr); /* see yyrealloc() for (char *) cast */ |
| -} |
| - |
| #define YYTABLES_NAME "yytables" |
| |
| namespace angle |
| diff --git a/src/compiler/preprocessor/preprocessor_tab_autogen.cpp b/src/compiler/preprocessor/preprocessor_tab_autogen.cpp |
| index cfb4bc1b2a0113b0d6ea863be78fbbd60afd922c..8702d01fef25765c4778172a2a45cd5e54addbd8 100644 |
| --- a/src/compiler/preprocessor/preprocessor_tab_autogen.cpp |
| +++ b/src/compiler/preprocessor/preprocessor_tab_autogen.cpp |
| @@ -1,3 +1,6 @@ |
| +/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of |
| + * the BSD license. */ |
| + |
| /* A Bison parser, made by GNU Bison 3.8.2. */ |
| |
| /* Bison implementation for Yacc-like parsers in C |
| diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp |
| index 710bba9725dfddd970be1bc3e19ee91f18c7e359..33d4a644e82c58dc143fa43038e8b48ba81618c1 100644 |
| --- a/src/compiler/translator/IntermNode.cpp |
| +++ b/src/compiler/translator/IntermNode.cpp |
| @@ -880,7 +880,7 @@ const TConstantUnion *TIntermAggregate::getConstantValue() const |
| // http://crbug.com/498400132 |
| angle::base::CheckedNumeric<size_t> checkedArraySize = elementSize; |
| checkedArraySize *= getOutermostArraySize(); |
| - constArray = new TConstantUnion[checkedArraySize.ValueOrDie()]; |
| + constArray = new TConstantUnion[static_cast<size_t>(checkedArraySize.ValueOrDie())]; |
| |
| size_t elementOffset = 0u; |
| for (TIntermNode *constructorArg : mArguments) |
| diff --git a/src/compiler/translator/ShaderLang.cpp b/src/compiler/translator/ShaderLang.cpp |
| index d720455a25f5861dd79d1ca34b35944ce8044f6e..f4337e8088245f98e3db40d4db179cc5d5028188 100644 |
| --- a/src/compiler/translator/ShaderLang.cpp |
| +++ b/src/compiler/translator/ShaderLang.cpp |
| @@ -964,27 +964,7 @@ ShCompileOptions::ShCompileOptions() |
| memset(this, 0, sizeof(*this)); |
| } |
| |
| -ShCompileOptions::ShCompileOptions(const ShCompileOptions &other) |
| -{ |
| - memcpy(this, &other, sizeof(*this)); |
| -} |
| -ShCompileOptions &ShCompileOptions::operator=(const ShCompileOptions &other) |
| -{ |
| - memcpy(this, &other, sizeof(*this)); |
| - return *this; |
| -} |
| - |
| ShBuiltInResources::ShBuiltInResources() |
| { |
| memset(this, 0, sizeof(*this)); |
| } |
| - |
| -ShBuiltInResources::ShBuiltInResources(const ShBuiltInResources &other) |
| -{ |
| - memcpy(this, &other, sizeof(*this)); |
| -} |
| -ShBuiltInResources &ShBuiltInResources::operator=(const ShBuiltInResources &other) |
| -{ |
| - memcpy(this, &other, sizeof(*this)); |
| - return *this; |
| -} |
| diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h |
| index 105d99c4692e5cf4d3a15a53a228d855baf67d16..79f2eb49bf0480976ea34815550f8cce9b2ee40d 100644 |
| --- a/src/compiler/translator/Types.h |
| +++ b/src/compiler/translator/Types.h |
| @@ -257,6 +257,7 @@ class TType |
| bool isScalarBool() const { return isScalar() && type == EbtBool; } |
| bool isScalarFloat() const { return isScalar() && type == EbtFloat; } |
| bool isScalarInt() const { return isScalar() && (type == EbtInt || type == EbtUInt); } |
| + bool isSignedInt() const { return type == EbtInt; } |
| |
| bool canBeConstructed() const; |
| |
| diff --git a/src/compiler/translator/glslang.l b/src/compiler/translator/glslang.l |
| index efc341f799f5d2157ee50b0734ee163612fd185e..4bbcb5d303ce51a0b2d712fa9244c2d904a648aa 100644 |
| --- a/src/compiler/translator/glslang.l |
| +++ b/src/compiler/translator/glslang.l |
| @@ -49,6 +49,11 @@ WHICH GENERATES THE GLSL ES LEXER (glslang_lex_autogen.cpp). |
| #pragma clang diagnostic ignored "-Wextra-semi-stmt" |
| #pragma clang diagnostic ignored "-Wunreachable-code" |
| #endif |
| + |
| +// Rename yyalloc/yyrealloc/yyfree during flex generation to allow macro definitions. |
| +#define yyalloc yyalloc_FLEXGEN |
| +#define yyrealloc yyrealloc_FLEXGEN |
| +#define yyfree yyfree_FLEXGEN |
| } |
| |
| %{ |
| @@ -82,6 +87,14 @@ using namespace sh; |
| #define YY_INPUT(buf, result, max_size) \ |
| result = string_input(buf, max_size, yyscanner); |
| |
| +// Undefine renames and define yyalloc/yyrealloc/yyfree as macros for typed malloc support. |
| +#undef yyalloc |
| +#undef yyrealloc |
| +#undef yyfree |
| +#define yyalloc(size, yyscanner) malloc(size) |
| +#define yyrealloc(ptr, size, yyscanner) realloc((ptr), (size)) |
| +#define yyfree(ptr, yyscanner) free(ptr) |
| + |
| static yy_size_t string_input(char* buf, yy_size_t max_size, yyscan_t yyscanner); |
| static int check_type(yyscan_t yyscanner); |
| static int reserved_word(yyscan_t yyscanner); |
| @@ -120,6 +133,7 @@ static int floatsuffix_check(TParseContext* context); |
| static int yuvcscstandardext_constant(TParseContext *context); |
| %} |
| |
| +%option noyyalloc noyyrealloc noyyfree |
| %option noyywrap nounput never-interactive |
| %option yylineno reentrant bison-bridge bison-locations |
| %option extra-type="TParseContext*" |
| diff --git a/src/compiler/translator/glslang_lex_autogen.cpp b/src/compiler/translator/glslang_lex_autogen.cpp |
| index 6668b80f033c95955db975a02842c425d5cf7914..2cb1bb51f14fd8ec939de3b799ce60648c69d804 100644 |
| --- a/src/compiler/translator/glslang_lex_autogen.cpp |
| +++ b/src/compiler/translator/glslang_lex_autogen.cpp |
| @@ -35,6 +35,11 @@ |
| # pragma clang diagnostic ignored "-Wunreachable-code" |
| #endif |
| |
| +// Rename yyalloc/yyrealloc/yyfree during flex generation to allow macro definitions. |
| +#define yyalloc yyalloc_FLEXGEN |
| +#define yyrealloc yyrealloc_FLEXGEN |
| +#define yyfree yyfree_FLEXGEN |
| + |
| #define YY_INT_ALIGNED short int |
| |
| /* A lexical scanner generated by flex */ |
| @@ -919,6 +924,14 @@ using namespace sh; |
| |
| #define YY_INPUT(buf, result, max_size) result = string_input(buf, max_size, yyscanner); |
| |
| +// Undefine renames and define yyalloc/yyrealloc/yyfree as macros for typed malloc support. |
| +#undef yyalloc |
| +#undef yyrealloc |
| +#undef yyfree |
| +#define yyalloc(size, yyscanner) malloc(size) |
| +#define yyrealloc(ptr, size, yyscanner) realloc((ptr), (size)) |
| +#define yyfree(ptr, yyscanner) free(ptr) |
| + |
| static yy_size_t string_input(char *buf, yy_size_t max_size, yyscan_t yyscanner); |
| static int check_type(yyscan_t yyscanner); |
| static int reserved_word(yyscan_t yyscanner); |
| @@ -3882,35 +3895,6 @@ static int yy_flex_strlen(const char *s, yyscan_t yyscanner) |
| } |
| #endif |
| |
| -void *yyalloc(yy_size_t size, yyscan_t yyscanner) |
| -{ |
| - struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; |
| - (void)yyg; |
| - return malloc(size); |
| -} |
| - |
| -void *yyrealloc(void *ptr, yy_size_t size, yyscan_t yyscanner) |
| -{ |
| - struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; |
| - (void)yyg; |
| - |
| - /* The cast to (char *) in the following accommodates both |
| - * implementations that use char* generic pointers, and those |
| - * that use void* generic pointers. It works with the latter |
| - * because both ANSI C and C++ allow castless assignment from |
| - * any pointer type to void*, and deal with argument conversions |
| - * as though doing an assignment. |
| - */ |
| - return realloc(ptr, size); |
| -} |
| - |
| -void yyfree(void *ptr, yyscan_t yyscanner) |
| -{ |
| - struct yyguts_t *yyg = (struct yyguts_t *)yyscanner; |
| - (void)yyg; |
| - free((char *)ptr); /* see yyrealloc() for (char *) cast */ |
| -} |
| - |
| #define YYTABLES_NAME "yytables" |
| |
| yy_size_t string_input(char *buf, yy_size_t max_size, yyscan_t yyscanner) |
| diff --git a/src/compiler/translator/glslang_tab_autogen.cpp b/src/compiler/translator/glslang_tab_autogen.cpp |
| index 39c7613e355ea714e78fe178cff84a4da8393ae4..887d17be0dadf77a31d86dc885d2a45d50947579 100644 |
| --- a/src/compiler/translator/glslang_tab_autogen.cpp |
| +++ b/src/compiler/translator/glslang_tab_autogen.cpp |
| @@ -1,3 +1,6 @@ |
| +/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of |
| + * the BSD license. */ |
| + |
| /* A Bison parser, made by GNU Bison 3.8.2. */ |
| |
| /* Bison implementation for Yacc-like parsers in C |
| diff --git a/src/compiler/translator/glslang_tab_autogen.h b/src/compiler/translator/glslang_tab_autogen.h |
| index d5a48edd40f382359db76acf1a1ce75b6a6dc6d5..817bb46f9ca4b6fe0294c0fec72878a567c32ef6 100644 |
| --- a/src/compiler/translator/glslang_tab_autogen.h |
| +++ b/src/compiler/translator/glslang_tab_autogen.h |
| @@ -1,3 +1,6 @@ |
| +/* Apple Note: For the avoidance of doubt, Apple elects to distribute this file under the terms of |
| + * the BSD license. */ |
| + |
| /* A Bison parser, made by GNU Bison 3.8.2. */ |
| |
| /* Bison interface for Yacc-like parsers in C |
| diff --git a/src/compiler/translator/msl/EmitMetal.cpp b/src/compiler/translator/msl/EmitMetal.cpp |
| index 0cdc1bae0a16d62dd9ba7f56f26634797525ba5a..79711845904b8b51116148f823f356c69b7af975 100644 |
| --- a/src/compiler/translator/msl/EmitMetal.cpp |
| +++ b/src/compiler/translator/msl/EmitMetal.cpp |
| @@ -8,6 +8,7 @@ |
| # pragma allow_unsafe_buffers |
| #endif |
| |
| +#include <atomic> |
| #include <cctype> |
| #include <map> |
| |
| @@ -185,12 +186,17 @@ class GenMetalTraverser : public TIntermTraverser |
| |
| void emitSingleConstant(const TConstantUnion *const constUnion); |
| |
| + void emitForwardProgressStore(); |
| + void emitForwardProgressSignal(); |
| + bool shouldEnsureForwardProgress() const { return mForwardProgressStoreNestingCount >= 0; } |
| + |
| private: |
| Sink &mOut; |
| const TCompiler &mCompiler; |
| const PipelineStructs &mPipelineStructs; |
| SymbolEnv &mSymbolEnv; |
| IdGen &mIdGen; |
| + int mForwardProgressStoreNestingCount = -1; // Negative means forward progress is not ensured. |
| int mIndentLevel = -1; |
| int mLastIndentationPos = -1; |
| int mOpenPointerParenCount = 0; |
| @@ -205,8 +211,45 @@ class GenMetalTraverser : public TIntermTraverser |
| size_t mDriverUniformsBindingIndex = 0; |
| size_t mUBOArgumentBufferBindingIndex = 0; |
| bool mRasterOrderGroupsSupported = false; |
| - bool mInjectAsmStatementIntoLoopBodies = false; |
| + friend class ScopedForwardProgressStore; |
| +}; |
| + |
| +class ScopedForwardProgressStore |
| +{ |
| + public: |
| + ScopedForwardProgressStore(GenMetalTraverser &traverser); |
| + ~ScopedForwardProgressStore(); |
| + |
| + private: |
| + GenMetalTraverser &mTraverser; |
| }; |
| + |
| +ScopedForwardProgressStore::ScopedForwardProgressStore(GenMetalTraverser &traverser) |
| + : mTraverser(traverser) |
| +{ |
| + if (mTraverser.shouldEnsureForwardProgress()) |
| + { |
| + if (mTraverser.mForwardProgressStoreNestingCount == 0) |
| + { |
| + mTraverser.emitOpenBrace(); |
| + mTraverser.emitForwardProgressStore(); |
| + } |
| + ++mTraverser.mForwardProgressStoreNestingCount; |
| + } |
| +} |
| + |
| +ScopedForwardProgressStore::~ScopedForwardProgressStore() |
| +{ |
| + if (mTraverser.shouldEnsureForwardProgress()) |
| + { |
| + --mTraverser.mForwardProgressStoreNestingCount; |
| + if (mTraverser.mForwardProgressStoreNestingCount == 0) |
| + { |
| + mTraverser.emitCloseBrace(); |
| + } |
| + } |
| +} |
| + |
| } // anonymous namespace |
| |
| GenMetalTraverser::~GenMetalTraverser() |
| @@ -232,9 +275,13 @@ GenMetalTraverser::GenMetalTraverser(const TCompiler &compiler, |
| mDriverUniformsBindingIndex(compileOptions.metal.driverUniformsBindingIndex), |
| mUBOArgumentBufferBindingIndex(compileOptions.metal.UBOArgumentBufferBindingIndex), |
| mRasterOrderGroupsSupported(compileOptions.pls.fragmentSyncType == |
| - ShFragmentSynchronizationType::RasterOrderGroups_Metal), |
| - mInjectAsmStatementIntoLoopBodies(compileOptions.metal.injectAsmStatementIntoLoopBodies) |
| -{} |
| + ShFragmentSynchronizationType::RasterOrderGroups_Metal) |
| +{ |
| + if (compileOptions.metal.injectAsmStatementIntoLoopBodies) |
| + { |
| + mForwardProgressStoreNestingCount = 0; |
| + } |
| +} |
| |
| void GenMetalTraverser::emitIndentation() |
| { |
| @@ -283,19 +330,9 @@ static const char *GetOperatorString(TOperator op, |
| case TOperator::EOpInitialize: |
| return "="; |
| case TOperator::EOpAddAssign: |
| - return "+="; |
| + return resultType.isSignedInt() ? "ANGLE_addAssignInt" : "+="; |
| case TOperator::EOpSubAssign: |
| - return "-="; |
| - case TOperator::EOpMulAssign: |
| - return "*="; |
| - case TOperator::EOpDivAssign: |
| - return "/="; |
| - case TOperator::EOpIModAssign: |
| - return "%="; |
| - case TOperator::EOpBitShiftLeftAssign: |
| - return "<<="; // TODO: Check logical vs arithmetic shifting. |
| - case TOperator::EOpBitShiftRightAssign: |
| - return ">>="; // TODO: Check logical vs arithmetic shifting. |
| + return resultType.isSignedInt() ? "ANGLE_subAssignInt" : "-="; |
| case TOperator::EOpBitwiseAndAssign: |
| return "&="; |
| case TOperator::EOpBitwiseXorAssign: |
| @@ -303,19 +340,9 @@ static const char *GetOperatorString(TOperator op, |
| case TOperator::EOpBitwiseOrAssign: |
| return "|="; |
| case TOperator::EOpAdd: |
| - return "+"; |
| + return resultType.isSignedInt() ? "ANGLE_addInt" : "+"; |
| case TOperator::EOpSub: |
| - return "-"; |
| - case TOperator::EOpMul: |
| - return "*"; |
| - case TOperator::EOpDiv: |
| - return "/"; |
| - case TOperator::EOpIMod: |
| - return "%"; |
| - case TOperator::EOpBitShiftLeft: |
| - return "<<"; // TODO: Check logical vs arithmetic shifting. |
| - case TOperator::EOpBitShiftRight: |
| - return ">>"; // TODO: Check logical vs arithmetic shifting. |
| + return resultType.isSignedInt() ? "ANGLE_subInt" : "-"; |
| case TOperator::EOpBitwiseAnd: |
| return "&"; |
| case TOperator::EOpBitwiseXor: |
| @@ -360,23 +387,19 @@ static const char *GetOperatorString(TOperator op, |
| case TOperator::EOpBitwiseNot: |
| return "~"; |
| case TOperator::EOpPostIncrement: |
| - return "++"; |
| + return resultType.isSignedInt() ? "ANGLE_postIncrementInt" : "++"; |
| case TOperator::EOpPostDecrement: |
| - return "--"; |
| + return resultType.isSignedInt() ? "ANGLE_postDecrementInt" : "--"; |
| case TOperator::EOpPreIncrement: |
| - return "++"; |
| + return resultType.isSignedInt() ? "ANGLE_preIncrementInt" : "++"; |
| case TOperator::EOpPreDecrement: |
| - return "--"; |
| - case TOperator::EOpVectorTimesScalarAssign: |
| - return "*="; |
| + return resultType.isSignedInt() ? "ANGLE_preDecrementInt" : "--"; |
| case TOperator::EOpVectorTimesMatrixAssign: |
| return "*="; |
| case TOperator::EOpMatrixTimesScalarAssign: |
| return "*="; |
| case TOperator::EOpMatrixTimesMatrixAssign: |
| return "*="; |
| - case TOperator::EOpVectorTimesScalar: |
| - return "*"; |
| case TOperator::EOpVectorTimesMatrix: |
| return "*"; |
| case TOperator::EOpMatrixTimesVector: |
| @@ -390,6 +413,30 @@ static const char *GetOperatorString(TOperator op, |
| case TOperator::EOpNotEqualComponentWise: |
| return "!="; |
| |
| + case TOperator::EOpBitShiftRight: |
| + case TOperator::EOpBitShiftRightAssign: |
| + // TODO: Check logical vs arithmetic shifting. |
| + return "ANGLE_rshift"; |
| + |
| + case TOperator::EOpBitShiftLeft: |
| + case TOperator::EOpBitShiftLeftAssign: |
| + // TODO: Check logical vs arithmetic shifting. |
| + return resultType.isSignedInt() ? "ANGLE_ilshift" : "ANGLE_ulshift"; |
| + |
| + case TOperator::EOpMulAssign: |
| + case TOperator::EOpMul: |
| + case TOperator::EOpVectorTimesScalarAssign: |
| + case TOperator::EOpVectorTimesScalar: |
| + return resultType.isSignedInt() ? "ANGLE_imul" : "*"; |
| + |
| + case TOperator::EOpDiv: |
| + case TOperator::EOpDivAssign: |
| + return resultType.isSignedInt() ? "ANGLE_div" : "/"; |
| + |
| + case TOperator::EOpIMod: |
| + case TOperator::EOpIModAssign: |
| + return resultType.isSignedInt() ? "ANGLE_imod" : "%"; |
| + |
| case TOperator::EOpEqual: |
| if ((argType0->getStruct() && argType1->getStruct()) && |
| (argType0->isArray() && argType1->isArray())) |
| @@ -888,17 +935,14 @@ void GenMetalTraverser::emitPostQualifier(const EmitVariableDeclarationConfig &e |
| |
| void GenMetalTraverser::emitLoopBody(TIntermBlock *bodyNode) |
| { |
| - if (mInjectAsmStatementIntoLoopBodies) |
| + const bool emitForwardProgress = shouldEnsureForwardProgress(); |
| + if (emitForwardProgress) |
| { |
| emitOpenBrace(); |
| - |
| - emitIndentation(); |
| - mOut << "__asm__(\"\");\n"; |
| + emitForwardProgressSignal(); |
| } |
| - |
| bodyNode->traverse(this); |
| - |
| - if (mInjectAsmStatementIntoLoopBodies) |
| + if (emitForwardProgress) |
| { |
| emitCloseBrace(); |
| } |
| @@ -1819,6 +1863,18 @@ bool GenMetalTraverser::visitBinary(Visit, TIntermBinary *binaryNode) |
| } |
| break; |
| |
| + case TOperator::EOpDivAssign: |
| + case TOperator::EOpIModAssign: |
| + case TOperator::EOpBitShiftRightAssign: |
| + case TOperator::EOpBitShiftLeftAssign: |
| + case TOperator::EOpAddAssign: |
| + case TOperator::EOpSubAssign: |
| + case TOperator::EOpMulAssign: |
| + case TOperator::EOpVectorTimesScalarAssign: |
| + leftNode.traverse(this); |
| + mOut << " = "; |
| + [[fallthrough]]; |
| + |
| default: |
| { |
| const TType &resultType = binaryNode->getType(); |
| @@ -2255,7 +2311,31 @@ bool GenMetalTraverser::visitAggregate(Visit, TIntermAggregate *aggregateNode) |
| } |
| else |
| { |
| + bool isFtoi = [&]() { |
| + if ((!retType.isScalar() && !retType.isVector()) || |
| + !IsInteger(retType.getBasicType())) |
| + { |
| + return false; |
| + } |
| + if (aggregateNode->getChildCount() != 1) |
| + { |
| + return false; |
| + } |
| + auto &argType = aggregateNode->getChildNode(0)->getAsTyped()->getType(); |
| + return (argType.isScalar() || argType.isVector()) && |
| + argType.getBasicType() == EbtFloat; |
| + }(); |
| + |
| + if (isFtoi) |
| + { |
| + mOut << "ANGLE_ftoi<"; |
| emitType(retType, etConfig); |
| + mOut << ">"; |
| + } |
| + else |
| + { |
| + emitType(retType, etConfig); |
| + } |
| emitArgList("(", ")"); |
| } |
| |
| @@ -2380,6 +2460,26 @@ void GenMetalTraverser::emitCloseBrace() |
| mOut << "}"; |
| } |
| |
| +void GenMetalTraverser::emitForwardProgressStore() |
| +{ |
| + // https://eel.is/c++draft/intro.progress |
| + // "The implementation may assume that any thread will eventually do one of the following:"" |
| + // - ... |
| + // - "perform an access through a volatile glvalue" |
| + // Emit a volatile variable which all loops in the stack will access. |
| + emitIndentation(); |
| + mOut << "volatile bool ANGLE_p;\n"; |
| +} |
| + |
| +void GenMetalTraverser::emitForwardProgressSignal() |
| +{ |
| + // Emit a read though the volatile variable. This marks the loop as making forward progress even |
| + // if the compiler can otherwise analyze it to be infinite. This ensures that the loop |
| + // has defined behavior. |
| + emitIndentation(); |
| + mOut << "(void) ANGLE_p;\n"; |
| +} |
| + |
| static bool RequiresSemicolonTerminator(TIntermNode &node) |
| { |
| if (node.getAsBlock()) |
| @@ -2581,6 +2681,8 @@ bool GenMetalTraverser::visitForLoop(TIntermLoop *loopNode) |
| TIntermTyped *condNode = loopNode->getCondition(); |
| TIntermTyped *exprNode = loopNode->getExpression(); |
| |
| + ScopedForwardProgressStore scopedProgress(*this); |
| + |
| mOut << "for ("; |
| |
| if (initNode) |
| @@ -2623,6 +2725,7 @@ bool GenMetalTraverser::visitWhileLoop(TIntermLoop *loopNode) |
| ASSERT(condNode); |
| ASSERT(!initNode && !exprNode); |
| |
| + ScopedForwardProgressStore scopedProgress(*this); |
| emitIndentation(); |
| mOut << "while ("; |
| condNode->traverse(this); |
| @@ -2642,6 +2745,7 @@ bool GenMetalTraverser::visitDoWhileLoop(TIntermLoop *loopNode) |
| ASSERT(condNode); |
| ASSERT(!initNode && !exprNode); |
| |
| + ScopedForwardProgressStore scopedProgress(*this); |
| emitIndentation(); |
| mOut << "do\n"; |
| emitLoopBody(loopNode->getBody()); |
| @@ -2721,7 +2825,7 @@ bool GenMetalTraverser::visitBranch(Visit, TIntermBranch *branchNode) |
| return false; |
| } |
| |
| -static size_t emitMetalCallCount = 0; |
| +static std::atomic<size_t> emitMetalCallCount = 0; |
| |
| bool sh::EmitMetal(TCompiler &compiler, |
| TIntermBlock &root, |
| diff --git a/src/compiler/translator/msl/ModifyStruct.cpp b/src/compiler/translator/msl/ModifyStruct.cpp |
| index 366ed366185ab0fb56057f75dfb6bce2b9ce8150..4353eb0999d2a1c877056d3d8e735d80b1f61c45 100644 |
| --- a/src/compiler/translator/msl/ModifyStruct.cpp |
| +++ b/src/compiler/translator/msl/ModifyStruct.cpp |
| @@ -880,6 +880,13 @@ bool SaturateScalarOrVectorCommon(ConvertStructState &state, |
| } |
| }); |
| } |
| + for (uint8_t d = dim; d < saturation; ++d) |
| + { |
| + state.addConversion([=](Access::Env &, OriginalAccess &, ModifiedAccess &m) { |
| + auto &m_ = AccessIndex(m, d); |
| + return Access{*CreateZeroNode(m_.getType()), m_}; |
| + }); |
| + } |
| |
| return true; |
| } |
| diff --git a/src/compiler/translator/msl/ProgramPrelude.cpp b/src/compiler/translator/msl/ProgramPrelude.cpp |
| index 652acfbd3a1cb7f0f20892f78ec3b89dceb8c47f..2243ad8c3bc1d1609b89b339f60dda970eadf582 100644 |
| --- a/src/compiler/translator/msl/ProgramPrelude.cpp |
| +++ b/src/compiler/translator/msl/ProgramPrelude.cpp |
| @@ -117,6 +117,13 @@ class ProgramPrelude : public TIntermTraverser |
| void degrees(); |
| void radians(); |
| void mod(); |
| + void div(); |
| + void imod(); |
| + void imul(); |
| + void ilshift(); |
| + void ulshift(); |
| + void rshift(); |
| + void ftoi(); |
| void postIncrementMatrix(); |
| void preIncrementMatrix(); |
| void postDecrementMatrix(); |
| @@ -280,6 +287,14 @@ class ProgramPrelude : public TIntermTraverser |
| void interpolateAtCentroid(); |
| void interpolateAtSample(); |
| void interpolateAtOffset(); |
| + void postIncrementInt(); |
| + void preIncrementInt(); |
| + void postDecrementInt(); |
| + void preDecrementInt(); |
| + void addInt(); |
| + void addAssignInt(); |
| + void subInt(); |
| + void subAssignInt(); |
| void loopForwardProgress(); |
| |
| private: |
| @@ -435,6 +450,116 @@ ANGLE_ALWAYS_INLINE X ANGLE_mod(X x, Y y) |
| } |
| )") |
| |
| +// Avoid undefined behavior when: |
| +// - the divisor is 0 |
| +// - the dividend is INT_MIN and the divisor is -1 (integer overflow) |
| +// When the behavior would be undefined the result is `x`. |
| +// FIXME: This function should also handle INT_MIN / -1, but currently this hits a bug in the metal |
| +// compiler |
| +PROGRAM_PRELUDE_DECLARE(div, |
| + R"( |
| +template<typename X, typename Y, typename Z = metal::conditional_t<metal::is_scalar_v<Y>, X, Y>> |
| +ANGLE_ALWAYS_INLINE Z ANGLE_div(X x, Y y) |
| +{ |
| + Z zx = Z(x); |
| + Z zy = Z(y); |
| + auto predicate = zy == Z(0); |
| + return zx / metal::select(zy, Z(1), predicate); |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior when: |
| +// - the divisor is 0 |
| +// - the dividend is INT_MIN and the divisor is -1 (integer overflow) |
| +// - either of the operands is negative (undefined behavior in Metal) |
| +// When the behavior would be undefined the result is 0. |
| +// FIXME: This function should also handle INT_MIN % -1, but currently this hits a bug in the metal |
| +// compiler |
| +PROGRAM_PRELUDE_DECLARE(imod, |
| + R"( |
| +template<typename X, typename Y, typename Z = metal::conditional_t<metal::is_scalar_v<Y>, X, Y>> |
| +ANGLE_ALWAYS_INLINE Z ANGLE_imod(X x, Y y) |
| +{ |
| + if constexpr (metal::is_signed_v<Z>) { |
| + Z y_or_one = metal::select(Z(y), Z(1), Z(y) == Z(0)); |
| + if (metal::any(((Z(x) | y_or_one) & Z(2147483648u)) != Z(0u))) |
| + { |
| + return as_type<Z>( |
| + metal::make_unsigned_t<Z>(x) - metal::make_unsigned_t<Z>(x / y_or_one) * metal::make_unsigned_t<Z>(y_or_one) |
| + ); |
| + } |
| + else |
| + { |
| + return x % y_or_one; |
| + } |
| + } |
| + else |
| + { |
| + return x % metal::select(Z(y), Z(1u), Z(y) == Z(0u)); |
| + } |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior when the operand is outside the range of values that can be represented. |
| +// When the behavior would be undefined the value is clamped to fit the target type. |
| +PROGRAM_PRELUDE_DECLARE(ftoi, |
| + R"( |
| +template <typename X, typename Y> |
| +ANGLE_ALWAYS_INLINE X ANGLE_ftoi(Y y) |
| +{ |
| + auto min = metal::numeric_limits<X>::min(); |
| + auto max = metal::numeric_limits<X>::max(); |
| + return X(metal::clamp(y, Y(min), Y(max))); |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior due to integer overflow |
| +PROGRAM_PRELUDE_DECLARE(imul, |
| + R"( |
| +template<typename X, typename Y, typename Z = metal::conditional_t<metal::is_scalar_v<Y>, X, Y>> |
| +ANGLE_ALWAYS_INLINE Z ANGLE_imul(X x, Y y) |
| +{ |
| + return as_type<Z>(metal::make_unsigned_t<Z>(x) * metal::make_unsigned_t<Z>(y)); |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior in e1 << e2 when: |
| +// 1) e2 is larger than the bit width of the type |
| +// 2) e2 is a negative value. |
| +// 3) e1 is a negative value |
| +PROGRAM_PRELUDE_DECLARE(ilshift, |
| + R"( |
| +template <typename X, typename Y> |
| +ANGLE_ALWAYS_INLINE X ANGLE_ilshift(X x, Y y) |
| +{ |
| + return as_type<X>(metal::select(metal::make_unsigned_t<X>(0), metal::make_unsigned_t<X>(x) << (y & Y(31)), metal::make_unsigned_t<Y>(y) < metal::make_unsigned_t<Y>(32))); |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior in e1 << e2 when: |
| +// 1) e2 is larger than the bit width of the type |
| +// 2) e2 is a negative value. |
| +PROGRAM_PRELUDE_DECLARE(ulshift, |
| + R"( |
| +template <typename X, typename Y> |
| +ANGLE_ALWAYS_INLINE X ANGLE_ulshift(X x, Y y) |
| +{ |
| + return metal::select(X(0), x << (y & Y(31)), metal::make_unsigned_t<Y>(y) < metal::make_unsigned_t<Y>(32)); |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior in e1 >> e2 when: |
| +// 1) e2 is larger than the bit width of the type |
| +// 2) e2 is a negative value. |
| +PROGRAM_PRELUDE_DECLARE(rshift, |
| + R"( |
| +template <typename X, typename Y> |
| +ANGLE_ALWAYS_INLINE X ANGLE_rshift(X x, Y y) |
| +{ |
| + return metal::select(X(0), x >> (y & Y(31)), metal::make_unsigned_t<Y>(y) < metal::make_unsigned_t<Y>(32)); |
| +} |
| +)") |
| + |
| PROGRAM_PRELUDE_DECLARE(pack_half_2x16, |
| R"( |
| ANGLE_ALWAYS_INLINE uint32_t ANGLE_pack_half_2x16(float2 v) |
| @@ -2763,6 +2888,164 @@ template <typename T> |
| ANGLE_ALWAYS_INLINE T ANGLE_interpolateAtOffset(T value, float2) { return value; } |
| )") |
| |
| +PROGRAM_PRELUDE_DECLARE(preIncrementInt, |
| + R"( |
| +ANGLE_ALWAYS_INLINE int ANGLE_preIncrementInt(thread int &a) |
| +{ |
| + a = as_type<int>(as_type<metal::uint>(a) + 1u); |
| + return a; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int2 ANGLE_preIncrementInt(thread metal::int2 &a) |
| +{ |
| + a = as_type<metal::int2>(as_type<metal::uint2>(a) + 1u); |
| + return a; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int3 ANGLE_preIncrementInt(thread metal::int3 &a) |
| +{ |
| + a = as_type<metal::int3>(as_type<metal::uint3>(a) + 1u); |
| + return a; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int4 ANGLE_preIncrementInt(thread metal::int4 &a) |
| +{ |
| + a = as_type<metal::int4>(as_type<metal::uint4>(a) + 1u); |
| + return a; |
| +} |
| +)") |
| + |
| +PROGRAM_PRELUDE_DECLARE(postIncrementInt, |
| + R"( |
| +ANGLE_ALWAYS_INLINE int ANGLE_postIncrementInt(thread int &a) |
| +{ |
| + int r = a; |
| + a = as_type<int>(as_type<metal::uint>(a) + 1u); |
| + return r; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int2 ANGLE_postIncrementInt(thread metal::int2 &a) |
| +{ |
| + metal::int2 r = a; |
| + a = as_type<metal::int2>(as_type<metal::uint2>(a) + 1u); |
| + return r; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int3 ANGLE_postIncrementInt(thread metal::int3 &a) |
| +{ |
| + metal::int3 r = a; |
| + a = as_type<metal::int3>(as_type<metal::uint3>(a) + 1u); |
| + return r; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int4 ANGLE_postIncrementInt(thread metal::int4 &a) |
| +{ |
| + metal::int4 r = a; |
| + a = as_type<metal::int4>(as_type<metal::uint4>(a) + 1u); |
| + return r; |
| +} |
| +)") |
| + |
| +PROGRAM_PRELUDE_DECLARE(preDecrementInt, |
| + R"( |
| +ANGLE_ALWAYS_INLINE int ANGLE_preDecrementInt(thread int &a) |
| +{ |
| + a = as_type<int>(as_type<metal::uint>(a) - 1u); |
| + return a; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int2 ANGLE_preDecrementInt(thread metal::int2 &a) |
| +{ |
| + a = as_type<metal::int2>(as_type<metal::uint2>(a) - 1u); |
| + return a; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int3 ANGLE_preDecrementInt(thread metal::int3 &a) |
| +{ |
| + a = as_type<metal::int3>(as_type<metal::uint3>(a) - 1u); |
| + return a; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int4 ANGLE_preDecrementInt(thread metal::int4 &a) |
| +{ |
| + a = as_type<metal::int4>(as_type<metal::uint4>(a) - 1u); |
| + return a; |
| +} |
| +)") |
| + |
| +PROGRAM_PRELUDE_DECLARE(postDecrementInt, |
| + R"( |
| +ANGLE_ALWAYS_INLINE int ANGLE_postDecrementInt(thread int &a) |
| +{ |
| + int r = a; |
| + a = as_type<int>(as_type<metal::uint>(a) - 1u); |
| + return r; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int2 ANGLE_postDecrementInt(thread metal::int2 &a) |
| +{ |
| + metal::int2 r = a; |
| + a = as_type<metal::int2>(as_type<metal::uint2>(a) - 1u); |
| + return r; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int3 ANGLE_postDecrementInt(thread metal::int3 &a) |
| +{ |
| + metal::int3 r = a; |
| + a = as_type<metal::int3>(as_type<metal::uint3>(a) - 1u); |
| + return r; |
| +} |
| + |
| +ANGLE_ALWAYS_INLINE metal::int4 ANGLE_postDecrementInt(thread metal::int4 &a) |
| +{ |
| + metal::int4 r = a; |
| + a = as_type<metal::int4>(as_type<metal::uint4>(a) - 1u); |
| + return r; |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior due to integer overflow. |
| +PROGRAM_PRELUDE_DECLARE(addInt, |
| + R"( |
| +template<typename X, typename Y, typename Z = metal::conditional_t<metal::is_scalar_v<Y>, X, Y>> |
| +ANGLE_ALWAYS_INLINE Z ANGLE_addInt(X x, Y y) |
| +{ |
| + return as_type<Z>(metal::make_unsigned_t<Z>(x) + metal::make_unsigned_t<Z>(y)); |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior due to integer overflow. |
| +PROGRAM_PRELUDE_DECLARE(addAssignInt, |
| + R"( |
| +template<typename X, typename Y> |
| +ANGLE_ALWAYS_INLINE thread X &ANGLE_addAssignInt(thread X &x, Y y) |
| +{ |
| + x = as_type<X>(metal::make_unsigned_t<X>(x) + metal::make_unsigned_t<Y>(y)); |
| + return x; |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior due to integer underflow. |
| +PROGRAM_PRELUDE_DECLARE(subInt, |
| + R"( |
| +template<typename X, typename Y, typename Z = metal::conditional_t<metal::is_scalar_v<Y>, X, Y>> |
| +ANGLE_ALWAYS_INLINE Z ANGLE_subInt(X x, Y y) |
| +{ |
| + return as_type<Z>(metal::make_unsigned_t<Z>(x) - metal::make_unsigned_t<Z>(y)); |
| +} |
| +)") |
| + |
| +// Avoid undefined behavior due to integer underflow. |
| +PROGRAM_PRELUDE_DECLARE(subAssignInt, |
| + R"( |
| +template<typename X, typename Y> |
| +ANGLE_ALWAYS_INLINE thread X &ANGLE_subAssignInt(thread X &x, Y y) |
| +{ |
| + x = as_type<X>(metal::make_unsigned_t<X>(x) - metal::make_unsigned_t<Y>(y)); |
| + return x; |
| +} |
| +)") |
| + |
| PROGRAM_PRELUDE_DECLARE(loopForwardProgress, |
| R"( |
| ANGLE_ALWAYS_INLINE void ANGLE_loopForwardProgress() |
| @@ -3282,6 +3565,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| case TOperator::EOpMod: |
| mod(); |
| break; |
| + case TOperator::EOpIModAssign: |
| + case TOperator::EOpIMod: |
| + imod(); |
| + break; |
| case TOperator::EOpRefract: |
| if (argType0->isScalar()) |
| { |
| @@ -3426,6 +3713,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| addScalarMatrix(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + addInt(); |
| + } |
| break; |
| |
| case TOperator::EOpAddAssign: |
| @@ -3433,6 +3724,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| addMatrixScalarAssign(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + addAssignInt(); |
| + } |
| break; |
| |
| case TOperator::EOpSub: |
| @@ -3444,6 +3739,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| subScalarMatrix(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + subInt(); |
| + } |
| break; |
| |
| case TOperator::EOpSubAssign: |
| @@ -3451,9 +3750,28 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| subMatrixScalarAssign(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + subAssignInt(); |
| + } |
| + break; |
| + |
| + case TOperator::EOpMul: |
| + case TOperator::EOpMulAssign: |
| + case TOperator::EOpVectorTimesScalar: |
| + case TOperator::EOpVectorTimesScalarAssign: |
| + if (argType0->isSignedInt()) |
| + { |
| + imul(); |
| + } |
| + if (argType0->isSignedInt()) |
| + { |
| + subAssignInt(); |
| + } |
| break; |
| |
| case TOperator::EOpDiv: |
| + case TOperator::EOpDivAssign: |
| if (argType1->isMatrix()) |
| { |
| if (argType0->isMatrix()) |
| @@ -3465,12 +3783,9 @@ void ProgramPrelude::visitOperator(TOperator op, |
| divScalarMatrix(); |
| } |
| } |
| - break; |
| - |
| - case TOperator::EOpDivAssign: |
| - if (argType0->isMatrix() && argType1->isMatrix()) |
| + else |
| { |
| - componentWiseDivideAssign(); |
| + div(); |
| } |
| break; |
| |
| @@ -3511,6 +3826,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| preIncrementMatrix(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + preIncrementInt(); |
| + } |
| break; |
| |
| case TOperator::EOpPostIncrement: |
| @@ -3518,6 +3837,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| postIncrementMatrix(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + postIncrementInt(); |
| + } |
| break; |
| |
| case TOperator::EOpPreDecrement: |
| @@ -3525,6 +3848,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| preDecrementMatrix(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + preDecrementInt(); |
| + } |
| break; |
| |
| case TOperator::EOpPostDecrement: |
| @@ -3532,6 +3859,10 @@ void ProgramPrelude::visitOperator(TOperator op, |
| { |
| postDecrementMatrix(); |
| } |
| + if (argType0->isSignedInt()) |
| + { |
| + postDecrementInt(); |
| + } |
| break; |
| |
| case TOperator::EOpNegative: |
| @@ -3541,20 +3872,31 @@ void ProgramPrelude::visitOperator(TOperator op, |
| } |
| break; |
| |
| + case TOperator::EOpBitShiftLeft: |
| + case TOperator::EOpBitShiftLeftAssign: |
| + { |
| + if (argType0->isSignedInt()) |
| + { |
| + ilshift(); |
| + } |
| + else |
| + { |
| + ulshift(); |
| + } |
| + break; |
| + } |
| + |
| + case TOperator::EOpBitShiftRight: |
| + case TOperator::EOpBitShiftRightAssign: |
| + rshift(); |
| + break; |
| + |
| case TOperator::EOpComma: |
| case TOperator::EOpAssign: |
| case TOperator::EOpInitialize: |
| - case TOperator::EOpMulAssign: |
| - case TOperator::EOpIModAssign: |
| - case TOperator::EOpBitShiftLeftAssign: |
| - case TOperator::EOpBitShiftRightAssign: |
| case TOperator::EOpBitwiseAndAssign: |
| case TOperator::EOpBitwiseXorAssign: |
| case TOperator::EOpBitwiseOrAssign: |
| - case TOperator::EOpMul: |
| - case TOperator::EOpIMod: |
| - case TOperator::EOpBitShiftLeft: |
| - case TOperator::EOpBitShiftRight: |
| case TOperator::EOpBitwiseAnd: |
| case TOperator::EOpBitwiseXor: |
| case TOperator::EOpBitwiseOr: |
| @@ -3573,10 +3915,8 @@ void ProgramPrelude::visitOperator(TOperator op, |
| case TOperator::EOpLogicalNot: |
| case TOperator::EOpNotComponentWise: |
| case TOperator::EOpBitwiseNot: |
| - case TOperator::EOpVectorTimesScalarAssign: |
| case TOperator::EOpVectorTimesMatrixAssign: |
| case TOperator::EOpMatrixTimesScalarAssign: |
| - case TOperator::EOpVectorTimesScalar: |
| case TOperator::EOpVectorTimesMatrix: |
| case TOperator::EOpMatrixTimesVector: |
| case TOperator::EOpMatrixTimesScalar: |
| @@ -3748,6 +4088,17 @@ bool ProgramPrelude::visitAggregate(Visit visit, TIntermAggregate *node) |
| |
| const TFunction *func = node->getFunction(); |
| |
| + if (node->isConstructor() && argCount == 1) |
| + { |
| + const TType &retType = node->getType(); |
| + const TType &argType = getArgType(0); |
| + if (((retType.isScalar() || retType.isVector()) && IsInteger(retType.getBasicType())) && |
| + ((argType.isScalar() || argType.isVector()) && argType.getBasicType() == EbtFloat)) |
| + { |
| + ftoi(); |
| + } |
| + } |
| + |
| switch (node->getChildCount()) |
| { |
| case 0: |
| diff --git a/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp b/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp |
| index 77262ed6e5b598fde791b1b4b9ce9e76afaf288f..43b2ebb619854abc14e5db8ceda6feab5e73ef24 100644 |
| --- a/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp |
| +++ b/src/compiler/translator/tree_ops/RewriteStructSamplers.cpp |
| @@ -39,18 +39,19 @@ using StructureMap = angle::HashMap<const TStructure *, StructureData>; |
| using StructureUniformMap = angle::HashMap<const TVariable *, const TVariable *>; |
| using ExtractedSamplerMap = angle::HashMap<std::string, const TVariable *>; |
| |
| -TIntermTyped *RewriteModifiedStructFieldSelectionExpression( |
| - TCompiler *compiler, |
| +bool RewriteModifiedStructFieldSelectionExpression(TCompiler *compiler, |
| TIntermBinary *node, |
| const StructureMap &structureMap, |
| const StructureUniformMap &structureUniformMap, |
| - const ExtractedSamplerMap &extractedSamplers); |
| + const ExtractedSamplerMap &extractedSamplers, |
| + TIntermTyped **rewritten); |
| |
| -TIntermTyped *RewriteExpressionVisitBinaryHelper(TCompiler *compiler, |
| +bool RewriteExpressionVisitBinaryHelper(TCompiler *compiler, |
| TIntermBinary *node, |
| const StructureMap &structureMap, |
| const StructureUniformMap &structureUniformMap, |
| - const ExtractedSamplerMap &extractedSamplers) |
| + const ExtractedSamplerMap &extractedSamplers, |
| + TIntermTyped **rewritten) |
| { |
| // Only interested in EOpIndex* binary nodes. |
| switch (node->getOp()) |
| @@ -61,20 +62,22 @@ TIntermTyped *RewriteExpressionVisitBinaryHelper(TCompiler *compiler, |
| case EOpIndexDirectStruct: |
| break; |
| default: |
| - return nullptr; |
| + *rewritten = nullptr; |
| + return true; |
| } |
| |
| const TStructure *structure = node->getLeft()->getType().getStruct(); |
| if (structure == nullptr) |
| { |
| - return nullptr; |
| + return true; |
| } |
| |
| // If the result of the index is not a sampler and the struct is not replaced, there's nothing |
| // to do. |
| if (!node->getType().isSampler() && structureMap.find(structure) == structureMap.end()) |
| { |
| - return nullptr; |
| + *rewritten = nullptr; |
| + return true; |
| } |
| |
| // Otherwise, replace the whole expression such that: |
| @@ -84,8 +87,13 @@ TIntermTyped *RewriteExpressionVisitBinaryHelper(TCompiler *compiler, |
| // the intermediate nodes would have the correct type (and therefore fields). |
| ASSERT(structureMap.find(structure) != structureMap.end()); |
| |
| - return RewriteModifiedStructFieldSelectionExpression(compiler, node, structureMap, |
| - structureUniformMap, extractedSamplers); |
| + if (!RewriteModifiedStructFieldSelectionExpression( |
| + compiler, node, structureMap, structureUniformMap, extractedSamplers, rewritten)) |
| + { |
| + return false; |
| + } |
| + |
| + return true; |
| } |
| |
| // Given an expression, this traverser calculates a new expression where sampler-in-structs are |
| @@ -103,13 +111,19 @@ class RewriteExpressionTraverser final : public TIntermTraverser |
| mCompiler(compiler), |
| mStructureMap(structureMap), |
| mStructureUniformMap(structureUniformMap), |
| - mExtractedSamplers(extractedSamplers) |
| + mExtractedSamplers(extractedSamplers), |
| + mUnsupportedError(false) |
| {} |
| |
| bool visitBinary(Visit visit, TIntermBinary *node) override |
| { |
| - TIntermTyped *rewritten = RewriteExpressionVisitBinaryHelper( |
| - mCompiler, node, mStructureMap, mStructureUniformMap, mExtractedSamplers); |
| + TIntermTyped *rewritten = nullptr; |
| + if (!RewriteExpressionVisitBinaryHelper(mCompiler, node, mStructureMap, |
| + mStructureUniformMap, mExtractedSamplers, |
| + &rewritten)) |
| + { |
| + mUnsupportedError = true; |
| + } |
| |
| if (rewritten == nullptr) |
| { |
| @@ -138,6 +152,11 @@ class RewriteExpressionTraverser final : public TIntermTraverser |
| const StructureMap &mStructureMap; |
| const StructureUniformMap &mStructureUniformMap; |
| const ExtractedSamplerMap &mExtractedSamplers; |
| + |
| + // FIXME: Used to communicate that an error occurred during the rewrite process that is |
| + // currently not supported so that a failure can be returned to callers of |
| + // sh::RewriteStructSamplers(). |
| + bool mUnsupportedError; |
| }; |
| |
| // Rewrite the index of an EOpIndexIndirect expression. The root can never need replacing, because |
| @@ -179,12 +198,12 @@ void RewriteIndexExpression(TCompiler *compiler, |
| // |
| // If the expression is not a sampler, it only replaces the struct with the modified one, while |
| // still processing the EOpIndexIndirect expressions (which may contain more structs to map). |
| -TIntermTyped *RewriteModifiedStructFieldSelectionExpression( |
| - TCompiler *compiler, |
| +bool RewriteModifiedStructFieldSelectionExpression(TCompiler *compiler, |
| TIntermBinary *node, |
| const StructureMap &structureMap, |
| const StructureUniformMap &structureUniformMap, |
| - const ExtractedSamplerMap &extractedSamplers) |
| + const ExtractedSamplerMap &extractedSamplers, |
| + TIntermTyped **rewritten) |
| { |
| const bool isSampler = node->getType().isSampler(); |
| |
| @@ -221,18 +240,17 @@ TIntermTyped *RewriteModifiedStructFieldSelectionExpression( |
| iter = iter->getLeft()->getAsBinaryNode(); |
| } |
| |
| - TIntermTyped *rewritten = nullptr; |
| |
| if (isSampler) |
| { |
| ASSERT(extractedSamplers.find(samplerName) != extractedSamplers.end()); |
| - rewritten = new TIntermSymbol(extractedSamplers.at(samplerName)); |
| + *rewritten = new TIntermSymbol(extractedSamplers.at(samplerName)); |
| } |
| else |
| { |
| const TVariable *baseUniformVar = &baseUniform->variable(); |
| ASSERT(structureUniformMap.find(baseUniformVar) != structureUniformMap.end()); |
| - rewritten = new TIntermSymbol(structureUniformMap.at(baseUniformVar)); |
| + *rewritten = new TIntermSymbol(structureUniformMap.at(baseUniformVar)); |
| } |
| |
| // Iterate again and build the expression from bottom up. |
| @@ -245,13 +263,30 @@ TIntermTyped *RewriteModifiedStructFieldSelectionExpression( |
| case EOpIndexDirectStruct: |
| if (!isSampler) |
| { |
| - rewritten = |
| - new TIntermBinary(EOpIndexDirectStruct, rewritten, indexNode->getRight()); |
| + // FIXME: Fix accessing fields of structs containing other structs that only |
| + // contain samplers. Currently, given the following example definitions: |
| + // (e.g., struct S1 { sampler2D sampler; }; struct S2 { int i; S1 s; }; |
| + // uniform S2 uni;) |
| + // an out of bounds access can occur when trying to access uni.s.sampler because |
| + // s has been stripped out of the replacement structure definition for S2. For |
| + // now, check that indexing into the field list of a structure will not result |
| + // in an out of bounds array access before attempting to create the binary |
| + // operator node. |
| + const TFieldList &fields = (*rewritten)->getType().getStruct()->fields(); |
| + const size_t fieldIndex = |
| + indexNode->getRight()->getAsConstantUnion()->getIConst(0); |
| + if (fieldIndex >= fields.size()) |
| + { |
| + return false; |
| + } |
| + |
| + *rewritten = |
| + new TIntermBinary(EOpIndexDirectStruct, *rewritten, indexNode->getRight()); |
| } |
| break; |
| |
| case EOpIndexDirect: |
| - rewritten = new TIntermBinary(EOpIndexDirect, rewritten, indexNode->getRight()); |
| + *rewritten = new TIntermBinary(EOpIndexDirect, *rewritten, indexNode->getRight()); |
| break; |
| |
| case EOpIndexIndirect: |
| @@ -262,7 +297,7 @@ TIntermTyped *RewriteModifiedStructFieldSelectionExpression( |
| TIntermTyped *indexExpression = indexNode->getRight(); |
| RewriteIndexExpression(compiler, indexExpression, structureMap, structureUniformMap, |
| extractedSamplers); |
| - rewritten = new TIntermBinary(EOpIndexIndirect, rewritten, indexExpression); |
| + *rewritten = new TIntermBinary(EOpIndexIndirect, *rewritten, indexExpression); |
| break; |
| } |
| |
| @@ -272,7 +307,7 @@ TIntermTyped *RewriteModifiedStructFieldSelectionExpression( |
| } |
| } |
| |
| - return rewritten; |
| + return true; |
| } |
| |
| class RewriteStructSamplersTraverser final : public TIntermTraverser |
| @@ -281,7 +316,8 @@ class RewriteStructSamplersTraverser final : public TIntermTraverser |
| explicit RewriteStructSamplersTraverser(TCompiler *compiler, TSymbolTable *symbolTable) |
| : TIntermTraverser(true, false, false, symbolTable), |
| mCompiler(compiler), |
| - mRemovedUniformsCount(0) |
| + mRemovedUniformsCount(0), |
| + mUnsupportedError(false) |
| {} |
| |
| int removedUniformsCount() const { return mRemovedUniformsCount; } |
| @@ -344,8 +380,13 @@ class RewriteStructSamplersTraverser final : public TIntermTraverser |
| // Same implementation as in RewriteExpressionTraverser. That traverser cannot replace root. |
| bool visitBinary(Visit visit, TIntermBinary *node) override |
| { |
| - TIntermTyped *rewritten = RewriteExpressionVisitBinaryHelper( |
| - mCompiler, node, mStructureMap, mStructureUniformMap, mExtractedSamplers); |
| + TIntermTyped *rewritten = nullptr; |
| + if (!RewriteExpressionVisitBinaryHelper(mCompiler, node, mStructureMap, |
| + mStructureUniformMap, mExtractedSamplers, |
| + &rewritten)) |
| + { |
| + mUnsupportedError = true; |
| + } |
| |
| if (rewritten == nullptr) |
| { |
| @@ -369,6 +410,8 @@ class RewriteStructSamplersTraverser final : public TIntermTraverser |
| } |
| } |
| |
| + bool hasUnsupportedError() const { return mUnsupportedError; } |
| + |
| private: |
| bool isActiveUniform(const ImmutableString &rootStructureName) |
| { |
| @@ -635,6 +678,11 @@ class RewriteStructSamplersTraverser final : public TIntermTraverser |
| |
| // Caches the names of all inactive uniforms. |
| TSet<ImmutableString> *mActiveUniforms = nullptr; |
| + |
| + // FIXME: Used to communicate that an error occurred during the rewrite process that is |
| + // currently not |
| + // supported so that a failure can be returned to callers of sh::RewriteStructSamplers(). |
| + bool mUnsupportedError; |
| }; |
| } // anonymous namespace |
| |
| @@ -645,6 +693,10 @@ bool RewriteStructSamplers(TCompiler *compiler, |
| { |
| RewriteStructSamplersTraverser traverser(compiler, symbolTable); |
| root->traverse(&traverser); |
| + if (traverser.hasUnsupportedError()) |
| + { |
| + return false; |
| + } |
| *removedUniformsCountOut = traverser.removedUniformsCount(); |
| return traverser.updateTree(compiler, root); |
| } |
| diff --git a/src/compiler/translator/tree_ops/msl/RewriteUnaddressableReferences.cpp b/src/compiler/translator/tree_ops/msl/RewriteUnaddressableReferences.cpp |
| index 609f7a1f1e3bd96b2c0eb9188354bb207ec76f7c..a917f3c7ec6b2db1ba4bf0a39f39c7733f0de460 100644 |
| --- a/src/compiler/translator/tree_ops/msl/RewriteUnaddressableReferences.cpp |
| +++ b/src/compiler/translator/tree_ops/msl/RewriteUnaddressableReferences.cpp |
| @@ -135,17 +135,10 @@ bool ReturnsReference(TOperator op) |
| case TOperator::EOpBitwiseAndAssign: |
| case TOperator::EOpBitwiseXorAssign: |
| case TOperator::EOpBitwiseOrAssign: |
| - |
| - case TOperator::EOpPostIncrement: |
| - case TOperator::EOpPostDecrement: |
| - case TOperator::EOpPreIncrement: |
| - case TOperator::EOpPreDecrement: |
| - |
| case TOperator::EOpIndexDirect: |
| case TOperator::EOpIndexIndirect: |
| case TOperator::EOpIndexDirectStruct: |
| case TOperator::EOpIndexDirectInterfaceBlock: |
| - |
| return true; |
| |
| default: |
| @@ -153,6 +146,28 @@ bool ReturnsReference(TOperator op) |
| } |
| } |
| |
| +bool IsLValueUnaryOp(TOperator op) |
| +{ |
| + switch (op) |
| + { |
| + case EOpPostIncrement: |
| + case EOpPostDecrement: |
| + case EOpPreIncrement: |
| + case EOpPreDecrement: |
| + return true; |
| + case EOpNegative: |
| + case EOpPositive: |
| + case EOpLogicalNot: |
| + case EOpBitwiseNot: |
| + case EOpArrayLength: |
| + return false; |
| + default: |
| + break; |
| + } |
| + // At the time, we cannot use UNREACHABLE(); because builtin function calls might be unary ops. |
| + return false; |
| +} |
| + |
| TIntermTyped &DecomposeCompoundAssignment(TIntermBinary &node) |
| { |
| TOperator op = node.getOp(); |
| @@ -355,6 +370,23 @@ class Rewriter2 : public TIntermRebuild |
| *new TIntermSequence{&newLeft, &newRight}), |
| VisitBits::Neither}; |
| } |
| + |
| + PreResult visitUnaryPre(TIntermUnary &node) override |
| + { |
| + // Unary ++, -- operators for signed ints are implemented as functions. These take in a |
| + // reference. Addressing is needed to support swizzles. This can be removed when a pass is |
| + // added to replace the operators with builtin function calls. |
| + bool childRequiresAddressing = |
| + IsLValueUnaryOp(node.getOp()) && node.getType().isSignedInt(); |
| + mRequiresAddressingStack.push_back(childRequiresAddressing); |
| + return {node, VisitBits::Both}; |
| + } |
| + |
| + PostResult visitUnaryPost(TIntermUnary &node) override |
| + { |
| + mRequiresAddressingStack.pop_back(); |
| + return {node}; |
| + } |
| }; |
| |
| } // anonymous namespace |
| diff --git a/src/gpu_info_util/SystemInfo_internal.h b/src/gpu_info_util/SystemInfo_internal.h |
| index 5cef5d49eea1b1f1e6c22543446b2e5391ee88f2..5bfff7a4587126abada2d0a2560fb32cce79bd37 100644 |
| --- a/src/gpu_info_util/SystemInfo_internal.h |
| +++ b/src/gpu_info_util/SystemInfo_internal.h |
| @@ -41,11 +41,10 @@ uint64_t GetGpuIDFromDisplayID(uint32_t displayID); |
| uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask); |
| # endif |
| |
| -#endif |
| - |
| -#if defined(ANGLE_PLATFORM_MACOS) && ANGLE_ENABLE_METAL |
| +# if ANGLE_ENABLE_METAL |
| // Get VendorID from metal device's registry ID |
| VendorID GetVendorIDFromMetalDeviceRegistryID(uint64_t registryID); |
| +# endif |
| #endif |
| |
| |
| diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp |
| index f835683eb2144f6974bf66df9c8db7f6da68c0ce..00ecf6204dfe6743428dc0e811ff1e9037270217 100644 |
| --- a/src/libANGLE/Context.cpp |
| +++ b/src/libANGLE/Context.cpp |
| @@ -10070,6 +10070,33 @@ void Context::textureFoveationParameters(TextureID texturePacked, |
| texture->setFocalPoint(layer, focalPoint, focalX, focalY, gainX, gainY, foveaArea); |
| } |
| |
| +void Context::framebufferResolveRenderbufferWEBKIT(GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + RenderbufferID renderbuffer) |
| +{ |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + Framebuffer *framebuffer = mState.getTargetFramebuffer(target); |
| + ASSERT(framebuffer); |
| + |
| + if (renderbuffer.value != 0) |
| + { |
| + Renderbuffer *renderbufferObject = getRenderbuffer(renderbuffer); |
| + |
| + framebuffer->setAttachmentResolve(this, GL_RENDERBUFFER, attachment, gl::ImageIndex(), |
| + renderbufferObject); |
| + } |
| + else |
| + { |
| + framebuffer->resetAttachmentResolve(this, attachment); |
| + } |
| + |
| + mState.setObjectDirty(target); |
| +#else |
| + UNIMPLEMENTED(); |
| +#endif |
| +} |
| + |
| void Context::endTiling(GLbitfield preserveMask) |
| { |
| ANGLE_CONTEXT_TRY(mImplementation->endTiling(this, preserveMask)); |
| @@ -10144,6 +10171,16 @@ void Context::blobCacheCallbacks(GLSETBLOBPROCANGLE set, |
| mState.getBlobCacheCallbacks() = {set, get, userParam}; |
| } |
| |
| +void Context::bindMetalRasterizationRateMap(GLuint renderbufferHandle, |
| + GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + Renderbuffer *renderbuffer = getRenderbuffer({renderbufferHandle}); |
| + rx::RenderbufferImpl *renderbufferImpl = |
| + renderbuffer ? renderbuffer->getImplementation() : nullptr; |
| + ANGLE_CONTEXT_TRY(mImplementation->bindMetalRasterizationRateMap(this, renderbufferImpl, map)); |
| + getMutablePrivateState()->setVariableRasterizationRateMap(map); |
| +} |
| + |
| void Context::texStorageAttribs2D(GLenum target, |
| GLsizei levels, |
| GLenum internalFormat, |
| diff --git a/src/libANGLE/Context_gles_ext_autogen.h b/src/libANGLE/Context_gles_ext_autogen.h |
| index 57a6cbd81fcfce1072b168c72064e3022844724c..538e85131fc7e680e06581b2970a2241e3f892b6 100644 |
| --- a/src/libANGLE/Context_gles_ext_autogen.h |
| +++ b/src/libANGLE/Context_gles_ext_autogen.h |
| @@ -617,6 +617,8 @@ |
| /* GL_ANGLE_texture_compression_dxt5 */ \ |
| /* GL_ANGLE_texture_multisample */ \ |
| /* GL_ANGLE_texture_rectangle */ \ |
| + /* GL_ANGLE_variable_rasterization_rate_metal */ \ |
| + void bindMetalRasterizationRateMap(GLuint framebuffer, GLMTLRasterizationRateMapANGLE map); \ |
| /* GL_ANGLE_vulkan_image */ \ |
| void acquireTextures(GLuint numTextures, const TextureID *texturesPacked, \ |
| const GLenum *layouts); \ |
| @@ -643,6 +645,10 @@ |
| GLboolean unpackUnmultiplyAlpha); \ |
| /* GL_CHROMIUM_framebuffer_mixed_samples */ \ |
| /* GL_CHROMIUM_lose_context */ \ |
| - void loseContext(GraphicsResetStatus currentPacked, GraphicsResetStatus otherPacked); |
| + void loseContext(GraphicsResetStatus currentPacked, GraphicsResetStatus otherPacked); \ |
| + /* GL_WEBKIT_explicit_resolve_target */ \ |
| + void framebufferResolveRenderbufferWEBKIT(GLenum target, GLenum attachment, \ |
| + GLenum renderbuffertarget, \ |
| + RenderbufferID renderbufferPacked); |
| |
| #endif // ANGLE_CONTEXT_API_EXT_AUTOGEN_H_ |
| diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp |
| index e9821e504113395b31ff9c9ff2f5b480819ae349..eb5361dd4bcc583e85e4dc6ed9323b0d5706687b 100644 |
| --- a/src/libANGLE/Display.cpp |
| +++ b/src/libANGLE/Display.cpp |
| @@ -2370,7 +2370,7 @@ Error Display::validateImageClientBuffer(const gl::Context *context, |
| return mImplementation->validateImageClientBuffer(context, target, clientBuffer, attribs); |
| } |
| |
| -Error Display::valdiatePixmap(const Config *config, |
| +Error Display::validatePixmap(const Config *config, |
| EGLNativePixmapType pixmap, |
| const AttributeMap &attributes) const |
| { |
| diff --git a/src/libANGLE/Display.h b/src/libANGLE/Display.h |
| index aea0acc7cb8b630ee9092ffde7bfae8e46503b4b..5c6ff476f4f7328a806d159dac0a531b8b5f6431 100644 |
| --- a/src/libANGLE/Display.h |
| +++ b/src/libANGLE/Display.h |
| @@ -217,7 +217,7 @@ class Display final : public LabeledObject, |
| EGLenum target, |
| EGLClientBuffer clientBuffer, |
| const egl::AttributeMap &attribs) const; |
| - Error valdiatePixmap(const Config *config, |
| + Error validatePixmap(const Config *config, |
| EGLNativePixmapType pixmap, |
| const AttributeMap &attributes) const; |
| |
| diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp |
| index a88c0f1be428d1bb55a96a03440e46f4f72de495..fbc38a5a457c1ca0c305822ab35fd6b22f8b4abe 100644 |
| --- a/src/libANGLE/Framebuffer.cpp |
| +++ b/src/libANGLE/Framebuffer.cpp |
| @@ -131,6 +131,48 @@ FramebufferStatus CheckAttachmentCompleteness(const Context *context, |
| return FramebufferStatus::Complete(); |
| } |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| +// Check the |checkAttachment| in reference to |firstAttachment| for the sake of explicit resolve |
| +// target framebuffer completeness. |
| +FramebufferStatus CheckResolveTargetMatchesForCompleteness( |
| + const Context *context, |
| + const FramebufferAttachment &firstAttachment, |
| + const FramebufferAttachment &checkAttachment) |
| +{ |
| + ASSERT(firstAttachment.isAttached() && checkAttachment.isAttached()); |
| + |
| + FramebufferStatus attachmentCompleteness = |
| + CheckAttachmentCompleteness(context, checkAttachment); |
| + if (!attachmentCompleteness.isComplete()) |
| + { |
| + return attachmentCompleteness; |
| + } |
| + |
| + if (checkAttachment.getSamples() != 0) |
| + { |
| + return FramebufferStatus::Incomplete( |
| + GL_FRAMEBUFFER_UNSUPPORTED, |
| + "Framebuffer is incomplete: Resolve attachments have multiple samples."); |
| + } |
| + |
| + if (firstAttachment.getSize() != checkAttachment.getSize()) |
| + { |
| + return gl::FramebufferStatus::Incomplete( |
| + GL_FRAMEBUFFER_UNSUPPORTED, |
| + gl::err::kFramebufferIncompleteUnsupportedMissmatchedDimensions); |
| + } |
| + |
| + if (!Format::EquivalentForBlit(firstAttachment.getFormat(), checkAttachment.getFormat())) |
| + { |
| + return gl::FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNSUPPORTED, |
| + "Framebuffer is incomplete: Attempting to resolve " |
| + "to target with non-equivalent format for blit"); |
| + } |
| + |
| + return FramebufferStatus::Complete(); |
| +} |
| +#endif |
| + |
| FramebufferStatus CheckAttachmentSampleCounts(const Context *context, |
| GLsizei currAttachmentSamples, |
| GLsizei samples, |
| @@ -379,6 +421,9 @@ FramebufferState::FramebufferState(rx::UniqueSerial serial) |
| mFramebufferSerial(serial), |
| mLabel(), |
| mColorAttachments(1), |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + mColorResolveAttachments(1), |
| +#endif |
| mColorAttachmentsMask(0), |
| mDrawBufferStates(1, GL_NONE), |
| mReadBufferState(GL_BACK), |
| @@ -402,6 +447,9 @@ FramebufferState::FramebufferState(const Caps &caps, FramebufferID id, rx::Uniqu |
| mFramebufferSerial(serial), |
| mLabel(), |
| mColorAttachments(caps.maxColorAttachments), |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + mColorResolveAttachments(caps.maxColorAttachments), |
| +#endif |
| mColorAttachmentsMask(0), |
| mDrawBufferStates(caps.maxDrawBuffers, GL_NONE), |
| mReadBufferState(GL_COLOR_ATTACHMENT0_EXT), |
| @@ -572,6 +620,27 @@ const FramebufferAttachment *FramebufferState::getDepthStencilAttachment() const |
| return nullptr; |
| } |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| +const FramebufferAttachment *FramebufferState::getColorResolveAttachment( |
| + size_t colorAttachment) const |
| +{ |
| + ASSERT(colorAttachment < mColorResolveAttachments.size()); |
| + return mColorResolveAttachments[colorAttachment].isAttached() |
| + ? &mColorResolveAttachments[colorAttachment] |
| + : nullptr; |
| +} |
| + |
| +const FramebufferAttachment *FramebufferState::getDepthResolveAttachment() const |
| +{ |
| + return mDepthResolveAttachment.isAttached() ? &mDepthResolveAttachment : nullptr; |
| +} |
| + |
| +const FramebufferAttachment *FramebufferState::getStencilResolveAttachment() const |
| +{ |
| + return mStencilResolveAttachment.isAttached() ? &mStencilResolveAttachment : nullptr; |
| +} |
| +#endif |
| + |
| const Extents FramebufferState::getAttachmentExtentsIntersection() const |
| { |
| int32_t width = std::numeric_limits<int32_t>::max(); |
| @@ -802,6 +871,10 @@ Framebuffer::Framebuffer(const Context *context, rx::GLImplFactory *factory, Fra |
| ASSERT(mImpl != nullptr); |
| ASSERT(mState.mColorAttachments.size() == |
| static_cast<size_t>(context->getCaps().maxColorAttachments)); |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + ASSERT(mState.mColorResolveAttachments.size() == |
| + static_cast<size_t>(context->getCaps().maxColorAttachments)); |
| +#endif |
| |
| for (uint32_t colorIndex = 0; |
| colorIndex < static_cast<uint32_t>(mState.mColorAttachments.size()); ++colorIndex) |
| @@ -836,6 +909,15 @@ void Framebuffer::onDestroy(const Context *context) |
| mState.mWebGLStencilAttachment.detach(context, mState.mFramebufferSerial); |
| mState.mWebGLDepthStencilAttachment.detach(context, mState.mFramebufferSerial); |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + for (auto &attachment : mState.mColorResolveAttachments) |
| + { |
| + attachment.detach(context, mState.mFramebufferSerial); |
| + } |
| + mState.mDepthResolveAttachment.detach(context, mState.mFramebufferSerial); |
| + mState.mStencilResolveAttachment.detach(context, mState.mFramebufferSerial); |
| +#endif |
| + |
| if (mPixelLocalStorage) |
| { |
| mPixelLocalStorage->onFramebufferDestroyed(context); |
| @@ -1135,6 +1217,23 @@ size_t Framebuffer::getDrawbufferStateCount() const |
| return mState.mDrawBufferStates.size(); |
| } |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| +const FramebufferAttachment *Framebuffer::getColorResolveAttachment(size_t colorAttachment) const |
| +{ |
| + return mState.getColorResolveAttachment(colorAttachment); |
| +} |
| + |
| +const FramebufferAttachment *Framebuffer::getDepthResolveAttachment() const |
| +{ |
| + return mState.getDepthResolveAttachment(); |
| +} |
| + |
| +const FramebufferAttachment *Framebuffer::getStencilResolveAttachment() const |
| +{ |
| + return mState.getStencilResolveAttachment(); |
| +} |
| +#endif |
| + |
| GLenum Framebuffer::getDrawBufferState(size_t drawBuffer) const |
| { |
| ASSERT(drawBuffer < mState.mDrawBufferStates.size()); |
| @@ -1386,6 +1485,25 @@ FramebufferStatus Framebuffer::checkStatusWithGLFrontEnd(const Context *context) |
| } |
| } |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + for (size_t index = 0; index < mState.mColorAttachments.size(); ++index) |
| + { |
| + const FramebufferAttachment &colorAttachment = mState.mColorAttachments[index]; |
| + const FramebufferAttachment &colorResolveAttachment = |
| + mState.mColorResolveAttachments[index]; |
| + if (colorResolveAttachment.isAttached() && colorAttachment.isAttached()) |
| + { |
| + FramebufferStatus resolveAttachmentCompleteness = |
| + CheckResolveTargetMatchesForCompleteness(context, colorAttachment, |
| + colorResolveAttachment); |
| + if (!resolveAttachmentCompleteness.isComplete()) |
| + { |
| + return resolveAttachmentCompleteness; |
| + } |
| + } |
| + } |
| +#endif |
| + |
| const FramebufferAttachment &depthAttachment = mState.mDepthAttachment; |
| if (depthAttachment.isAttached()) |
| { |
| @@ -1439,6 +1557,20 @@ FramebufferStatus Framebuffer::checkStatusWithGLFrontEnd(const Context *context) |
| err::kFramebufferIncompleteMismatchedLayeredAttachments); |
| } |
| } |
| + |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + const FramebufferAttachment &depthResolveAttachment = mState.mDepthResolveAttachment; |
| + if (depthResolveAttachment.isAttached()) |
| + { |
| + FramebufferStatus resolveAttachmentCompleteness = |
| + CheckResolveTargetMatchesForCompleteness(context, depthAttachment, |
| + depthResolveAttachment); |
| + if (!resolveAttachmentCompleteness.isComplete()) |
| + { |
| + return resolveAttachmentCompleteness; |
| + } |
| + } |
| +#endif |
| } |
| |
| const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment; |
| @@ -1494,6 +1626,20 @@ FramebufferStatus Framebuffer::checkStatusWithGLFrontEnd(const Context *context) |
| err::kFramebufferIncompleteMismatchedLayeredAttachments); |
| } |
| } |
| + |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + const FramebufferAttachment &stencilResolveAttachment = mState.mStencilResolveAttachment; |
| + if (stencilResolveAttachment.isAttached()) |
| + { |
| + FramebufferStatus resolveAttachmentCompleteness = |
| + CheckResolveTargetMatchesForCompleteness(context, stencilAttachment, |
| + stencilResolveAttachment); |
| + if (!resolveAttachmentCompleteness.isComplete()) |
| + { |
| + return resolveAttachmentCompleteness; |
| + } |
| + } |
| +#endif |
| } |
| |
| // Starting from ES 3.0 stencil and depth, if present, should be the same image |
| @@ -2070,6 +2216,66 @@ void Framebuffer::setAttachmentMultisampleMultiview(const Context *context, |
| samples); |
| } |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| +void Framebuffer::setAttachmentResolve(const Context *context, |
| + GLenum type, |
| + GLenum binding, |
| + const ImageIndex &textureIndex, |
| + FramebufferAttachmentObject *resource) |
| +{ |
| + switch (binding) |
| + { |
| + case GL_DEPTH_STENCIL: |
| + case GL_DEPTH_STENCIL_ATTACHMENT: |
| + updateAttachmentResolve(context, &mState.mDepthResolveAttachment, |
| + DIRTY_BIT_DEPTH_ATTACHMENT, &mDirtyDepthAttachmentBinding, type, |
| + binding, textureIndex, resource); |
| + updateAttachmentResolve(context, &mState.mStencilResolveAttachment, |
| + DIRTY_BIT_STENCIL_ATTACHMENT, &mDirtyStencilAttachmentBinding, |
| + type, binding, textureIndex, resource); |
| + break; |
| + case GL_DEPTH: |
| + case GL_DEPTH_ATTACHMENT: |
| + updateAttachmentResolve(context, &mState.mDepthResolveAttachment, |
| + DIRTY_BIT_DEPTH_ATTACHMENT, &mDirtyDepthAttachmentBinding, type, |
| + binding, textureIndex, resource); |
| + if (context->isWebGL1()) |
| + { |
| + updateAttachmentResolve(context, &mState.mStencilResolveAttachment, |
| + DIRTY_BIT_STENCIL_ATTACHMENT, |
| + &mDirtyStencilAttachmentBinding, GL_NONE, |
| + GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr); |
| + } |
| + break; |
| + |
| + case GL_STENCIL: |
| + case GL_STENCIL_ATTACHMENT: |
| + updateAttachmentResolve(context, &mState.mStencilResolveAttachment, |
| + DIRTY_BIT_STENCIL_ATTACHMENT, &mDirtyStencilAttachmentBinding, |
| + type, binding, textureIndex, resource); |
| + if (context->isWebGL1()) |
| + { |
| + updateAttachmentResolve(context, &mState.mDepthResolveAttachment, |
| + DIRTY_BIT_DEPTH_ATTACHMENT, &mDirtyDepthAttachmentBinding, |
| + GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr); |
| + } |
| + break; |
| + |
| + default: |
| + { |
| + const size_t colorIndex = binding - GL_COLOR_ATTACHMENT0; |
| + ASSERT(colorIndex < mState.mColorResolveAttachments.size()); |
| + |
| + const size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex; |
| + updateAttachmentResolve(context, &mState.mColorResolveAttachments[colorIndex], dirtyBit, |
| + &mDirtyColorAttachmentBindings[colorIndex], type, binding, |
| + textureIndex, resource); |
| + } |
| + break; |
| + } |
| +} |
| +#endif |
| + |
| void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context, |
| GLsizei numViews, |
| GLuint baseViewIndex, |
| @@ -2247,11 +2453,40 @@ void Framebuffer::updateAttachment(const Context *context, |
| invalidateCompletenessCache(); |
| } |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| +void Framebuffer::updateAttachmentResolve(const Context *context, |
| + FramebufferAttachment *attachment, |
| + size_t dirtyBit, |
| + angle::ObserverBinding *onDirtyBinding, |
| + GLenum type, |
| + GLenum binding, |
| + const ImageIndex &textureIndex, |
| + FramebufferAttachmentObject *resource) |
| +{ |
| + attachment->attach( |
| + context, type, binding, textureIndex, resource, FramebufferAttachment::kDefaultNumViews, |
| + FramebufferAttachment::kDefaultBaseViewIndex, false, |
| + FramebufferAttachment::kDefaultRenderToTextureSamples, mState.mFramebufferSerial); |
| + mDirtyBits.set(dirtyBit); |
| + onDirtyBinding->bind(resource); |
| + mAttachmentChangedAfterEnablingFoveation = isFoveationEnabled(); |
| + |
| + invalidateCompletenessCache(); |
| +} |
| +#endif |
| + |
| void Framebuffer::resetAttachment(const Context *context, GLenum binding) |
| { |
| setAttachment(context, GL_NONE, binding, ImageIndex(), nullptr); |
| } |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| +void Framebuffer::resetAttachmentResolve(const Context *context, GLenum binding) |
| +{ |
| + setAttachmentResolve(context, GL_NONE, binding, ImageIndex(), nullptr); |
| +} |
| +#endif |
| + |
| void Framebuffer::setWriteControlMode(SrgbWriteControlMode srgbWriteControlMode) |
| { |
| if (srgbWriteControlMode != mState.getWriteControlMode()) |
| @@ -3089,4 +3324,5 @@ angle::Result Framebuffer::syncAttachmentState(const Context *context, |
| |
| return angle::Result::Continue; |
| } |
| + |
| } // namespace gl |
| diff --git a/src/libANGLE/Framebuffer.h b/src/libANGLE/Framebuffer.h |
| index 74c566497c8203ca5331e49817cf17dcf5ec0db4..561b1565fa008ac6163b622bb1a144d322ddfab7 100644 |
| --- a/src/libANGLE/Framebuffer.h |
| +++ b/src/libANGLE/Framebuffer.h |
| @@ -83,6 +83,13 @@ class FramebufferState final : angle::NonCopyable |
| const FramebufferAttachment *getDepthStencilAttachment() const; |
| const FramebufferAttachment *getReadPixelsAttachment(GLenum readFormat) const; |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + // GL_WEBKIT_explicit_resolve_target |
| + const FramebufferAttachment *getColorResolveAttachment(size_t colorAttachment) const; |
| + const FramebufferAttachment *getDepthResolveAttachment() const; |
| + const FramebufferAttachment *getStencilResolveAttachment() const; |
| +#endif |
| + |
| const DrawBuffersVector<GLenum> &getDrawBufferStates() const { return mDrawBufferStates; } |
| DrawBufferMask getEnabledDrawBuffers() const { return mEnabledDrawBuffers; } |
| GLenum getReadBufferState() const { return mReadBufferState; } |
| @@ -156,6 +163,13 @@ class FramebufferState final : angle::NonCopyable |
| FramebufferAttachment mDepthAttachment; |
| FramebufferAttachment mStencilAttachment; |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + // GL_WEBKIT_explicit_resolve_target; |
| + DrawBuffersVector<FramebufferAttachment> mColorResolveAttachments; |
| + FramebufferAttachment mDepthResolveAttachment; |
| + FramebufferAttachment mStencilResolveAttachment; |
| +#endif |
| + |
| // Tracks all the color buffers attached to this FramebufferDesc |
| DrawBufferMask mColorAttachmentsMask; |
| |
| @@ -246,6 +260,16 @@ class Framebuffer final : public angle::ObserverInterface, |
| GLint baseViewIndex); |
| void resetAttachment(const Context *context, GLenum binding); |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + // GL_WEBKIT_explicit_resolve_target |
| + void setAttachmentResolve(const Context *context, |
| + GLenum type, |
| + GLenum binding, |
| + const ImageIndex &textureIndex, |
| + FramebufferAttachmentObject *resource); |
| + void resetAttachmentResolve(const Context *context, GLenum binding); |
| +#endif |
| + |
| bool detachTexture(Context *context, TextureID texture); |
| bool detachRenderbuffer(Context *context, RenderbufferID renderbuffer); |
| |
| @@ -260,9 +284,16 @@ class Framebuffer final : public angle::ObserverInterface, |
| const FramebufferAttachment *getFirstColorAttachment() const; |
| const FramebufferAttachment *getFirstNonNullAttachment() const; |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + // GL_WEBKIT_explicit_resolve_target |
| + const FramebufferAttachment *getColorResolveAttachment(size_t colorAttachment) const; |
| + const FramebufferAttachment *getDepthResolveAttachment() const; |
| + const FramebufferAttachment *getStencilResolveAttachment() const; |
| +#endif |
| + |
| const DrawBuffersVector<FramebufferAttachment> &getColorAttachments() const |
| { |
| - return mState.mColorAttachments; |
| + return mState.getColorAttachments(); |
| } |
| |
| const FramebufferState &getState() const { return mState; } |
| @@ -537,6 +568,18 @@ class Framebuffer final : public angle::ObserverInterface, |
| bool isMultiview, |
| GLsizei samples); |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + // GL_WEBKIT_explicit_resolve_target |
| + void updateAttachmentResolve(const Context *context, |
| + FramebufferAttachment *attachment, |
| + size_t dirtyBit, |
| + angle::ObserverBinding *onDirtyBinding, |
| + GLenum type, |
| + GLenum binding, |
| + const ImageIndex &textureIndex, |
| + FramebufferAttachmentObject *resource); |
| +#endif |
| + |
| void markAttachmentsInitialized(const DrawBufferMask &color, bool depth, bool stencil); |
| void markAttachmentsUninitialized(const Context *context, |
| size_t count, |
| diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp |
| index c49645c46ed306325ed97b2857f5629b570cd961..f5b9c5a2ee1ec3be0a830f049cc11aa235d0ea9d 100644 |
| --- a/src/libANGLE/State.cpp |
| +++ b/src/libANGLE/State.cpp |
| @@ -10,6 +10,9 @@ |
| # pragma allow_unsafe_buffers |
| #endif |
| |
| +// Older clang versions have a false positive on this warning here. |
| +#pragma clang diagnostic ignored "-Wglobal-constructors" |
| + |
| #include "libANGLE/State.h" |
| |
| #include <string.h> |
| @@ -378,6 +381,8 @@ PrivateState::PrivateState(const Version &clientVersion, |
| mLogicOp(LogicalOperation::Copy), |
| mPatchVertices(3), |
| mPixelLocalStorageActivePlanes(0), |
| + mVariableRasterizationRateEnabled(false), |
| + mVariableRasterizationRateMap(nullptr), |
| mNoSimultaneousConstantColorAndAlphaBlendFunc(false), |
| mSetBlendIndexedInvoked(false), |
| mSetBlendFactorsIndexedInvoked(false), |
| @@ -1431,6 +1436,26 @@ void PrivateState::setLogicOp(LogicalOperation opcode) |
| } |
| } |
| |
| +void PrivateState::setVariableRasterizationRateEnabled(bool enabled) |
| +{ |
| + if (mVariableRasterizationRateEnabled != enabled) |
| + { |
| + mVariableRasterizationRateEnabled = enabled; |
| + mDirtyBits.set(state::DIRTY_BIT_EXTENDED); |
| + mExtendedDirtyBits.set(state::EXTENDED_DIRTY_BIT_VARIABLE_RASTERIZATION_RATE); |
| + } |
| +} |
| + |
| +void PrivateState::setVariableRasterizationRateMap(GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + if (mVariableRasterizationRateMap != map) |
| + { |
| + mVariableRasterizationRateMap = map; |
| + mDirtyBits.set(state::DIRTY_BIT_EXTENDED); |
| + mExtendedDirtyBits.set(state::EXTENDED_DIRTY_BIT_VARIABLE_RASTERIZATION_RATE); |
| + } |
| +} |
| + |
| void PrivateState::setVertexAttribf(GLuint index, const GLfloat values[4]) |
| { |
| ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size()); |
| @@ -1563,6 +1588,9 @@ void PrivateState::setEnableFeature(GLenum feature, bool enabled) |
| case GL_FETCH_PER_SAMPLE_ARM: |
| setFetchPerSample(enabled); |
| return; |
| + case GL_VARIABLE_RASTERIZATION_RATE_ANGLE: |
| + setVariableRasterizationRateEnabled(enabled); |
| + return; |
| default: |
| break; |
| } |
| @@ -1729,6 +1757,8 @@ bool PrivateState::getEnableFeature(GLenum feature) const |
| return mShadingRatePreserveAspectRatio; |
| case GL_FETCH_PER_SAMPLE_ARM: |
| return mFetchPerSample; |
| + case GL_VARIABLE_RASTERIZATION_RATE_ANGLE: |
| + return mVariableRasterizationRateEnabled; |
| } |
| |
| ASSERT(mClientVersion < ES_2_0); |
| @@ -3705,6 +3735,9 @@ void State::getPointerv(const Context *context, GLenum pname, void **params) con |
| case GL_BLOB_CACHE_USER_PARAM_ANGLE: |
| *params = const_cast<void *>(getBlobCacheCallbacks().userParam); |
| break; |
| + case GL_METAL_RASTERIZATION_RATE_MAP_BINDING_ANGLE: |
| + *params = privateState().getVariableRasterizationRateMap(); |
| + break; |
| default: |
| UNREACHABLE(); |
| break; |
| diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h |
| index 2676141f9deedcf1619d8f13e8a24aae12b4f162..730615c4499f0154201574cc5ec80c8bc176308d 100644 |
| --- a/src/libANGLE/State.h |
| +++ b/src/libANGLE/State.h |
| @@ -178,6 +178,7 @@ enum ExtendedDirtyBitType |
| EXTENDED_DIRTY_BIT_LOGIC_OP_ENABLED, // ANGLE_logic_op |
| EXTENDED_DIRTY_BIT_LOGIC_OP, // ANGLE_logic_op |
| EXTENDED_DIRTY_BIT_BLEND_ADVANCED_COHERENT, // KHR_blend_operation_advanced_coherent |
| + EXTENDED_DIRTY_BIT_VARIABLE_RASTERIZATION_RATE, // ANGLE_variable_rasterization_rate_metal |
| |
| EXTENDED_DIRTY_BIT_INVALID, |
| EXTENDED_DIRTY_BIT_MAX = EXTENDED_DIRTY_BIT_INVALID, |
| @@ -489,6 +490,15 @@ class PrivateState : angle::NonCopyable |
| bool hasActivelyOverriddenPLSDrawBuffers(GLint *firstActivePLSDrawBuffer) const; |
| bool isActivelyOverriddenPLSDrawBuffer(GLint drawbuffer) const; |
| |
| + // GL_ANGLE_variable_rasterization_rate_metal |
| + void setVariableRasterizationRateEnabled(bool enabled); |
| + bool isVariableRasterizationRateEnabled() const { return mVariableRasterizationRateEnabled; } |
| + void setVariableRasterizationRateMap(GLMTLRasterizationRateMapANGLE map); |
| + GLMTLRasterizationRateMapANGLE getVariableRasterizationRateMap() const |
| + { |
| + return mVariableRasterizationRateMap; |
| + } |
| + |
| // Line width state setter |
| void setLineWidth(GLfloat width); |
| float getLineWidth() const { return mLineWidth; } |
| @@ -779,6 +789,10 @@ class PrivateState : angle::NonCopyable |
| DrawBufferMask mPLSDeferredBlendEnables; |
| BlendStateExt::ColorMaskStorage::Type mPLSDeferredColorMasks; |
| |
| + // GL_ANGLE_variable_rasterization_rate_metal |
| + bool mVariableRasterizationRateEnabled; |
| + GLMTLRasterizationRateMapANGLE mVariableRasterizationRateMap; |
| + |
| // GLES1 emulation: state specific to GLES1 |
| GLES1State mGLES1State; |
| |
| diff --git a/src/libANGLE/capture/capture_gles_2_0_params.cpp b/src/libANGLE/capture/capture_gles_2_0_params.cpp |
| index 94dae050c7f768f0a341691e4180ce0fac7eb3ac..9d71c80612490990280683dd923f15f07eb0b0c8 100644 |
| --- a/src/libANGLE/capture/capture_gles_2_0_params.cpp |
| +++ b/src/libANGLE/capture/capture_gles_2_0_params.cpp |
| @@ -659,7 +659,6 @@ void CaptureTexImage2D_pixels(const State &glState, |
| |
| const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(format, type); |
| const gl::PixelUnpackState &unpack = glState.getUnpackState(); |
| - |
| GLuint srcRowPitch = 0; |
| GLuint srcDepthPitch = 0; |
| GLuint srcSkipBytes = 0; |
| diff --git a/src/libANGLE/capture/capture_gles_ext_autogen.cpp b/src/libANGLE/capture/capture_gles_ext_autogen.cpp |
| index b4a4ea014600d8894d070acb81e9237b9c1ac10d..5b9d4fa92fc5af560a5e12cec838248e11c684f2 100644 |
| --- a/src/libANGLE/capture/capture_gles_ext_autogen.cpp |
| +++ b/src/libANGLE/capture/capture_gles_ext_autogen.cpp |
| @@ -3982,6 +3982,20 @@ CallCapture CaptureGetTranslatedShaderSourceANGLE(const State &glState, |
| return CallCapture(angle::EntryPoint::GLGetTranslatedShaderSourceANGLE, std::move(paramBuffer)); |
| } |
| |
| +CallCapture CaptureBindMetalRasterizationRateMapANGLE(const State &glState, |
| + bool isCallValid, |
| + GLuint framebuffer, |
| + GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + ParamBuffer paramBuffer; |
| + |
| + paramBuffer.addValueParam("framebuffer", ParamType::TGLuint, framebuffer); |
| + paramBuffer.addValueParam("map", ParamType::TGLMTLRasterizationRateMapANGLE, map); |
| + |
| + return CallCapture(angle::EntryPoint::GLBindMetalRasterizationRateMapANGLE, |
| + std::move(paramBuffer)); |
| +} |
| + |
| CallCapture CaptureAcquireTexturesANGLE(const State &glState, |
| bool isCallValid, |
| GLuint numTextures, |
| @@ -10877,4 +10891,23 @@ CallCapture CaptureStartTilingQCOM(const State &glState, |
| return CallCapture(angle::EntryPoint::GLStartTilingQCOM, std::move(paramBuffer)); |
| } |
| |
| +CallCapture CaptureFramebufferResolveRenderbufferWEBKIT(const State &glState, |
| + bool isCallValid, |
| + GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + RenderbufferID renderbufferPacked) |
| +{ |
| + ParamBuffer paramBuffer; |
| + |
| + paramBuffer.addEnumParam("target", GLESEnum::AllEnums, ParamType::TGLenum, target); |
| + paramBuffer.addEnumParam("attachment", GLESEnum::AllEnums, ParamType::TGLenum, attachment); |
| + paramBuffer.addEnumParam("renderbuffertarget", GLESEnum::AllEnums, ParamType::TGLenum, |
| + renderbuffertarget); |
| + paramBuffer.addValueParam("renderbufferPacked", ParamType::TRenderbufferID, renderbufferPacked); |
| + |
| + return CallCapture(angle::EntryPoint::GLFramebufferResolveRenderbufferWEBKIT, |
| + std::move(paramBuffer)); |
| +} |
| + |
| } // namespace gl |
| diff --git a/src/libANGLE/capture/capture_gles_ext_autogen.h b/src/libANGLE/capture/capture_gles_ext_autogen.h |
| index 114b2bbad38e60da3e4d3f88bd648614f0e478ca..eae18b3bb570ef62ac9f698eb2c31f5b571e6952 100644 |
| --- a/src/libANGLE/capture/capture_gles_ext_autogen.h |
| +++ b/src/libANGLE/capture/capture_gles_ext_autogen.h |
| @@ -843,6 +843,12 @@ angle::CallCapture CaptureGetTranslatedShaderSourceANGLE(const State &glState, |
| GLsizei *length, |
| GLchar *source); |
| |
| +// GL_ANGLE_variable_rasterization_rate_metal |
| +angle::CallCapture CaptureBindMetalRasterizationRateMapANGLE(const State &glState, |
| + bool isCallValid, |
| + GLuint framebuffer, |
| + GLMTLRasterizationRateMapANGLE map); |
| + |
| // GL_ANGLE_vulkan_image |
| angle::CallCapture CaptureAcquireTexturesANGLE(const State &glState, |
| bool isCallValid, |
| @@ -2813,6 +2819,14 @@ angle::CallCapture CaptureStartTilingQCOM(const State &glState, |
| GLuint height, |
| GLbitfield preserveMask); |
| |
| +// GL_WEBKIT_explicit_resolve_target |
| +angle::CallCapture CaptureFramebufferResolveRenderbufferWEBKIT(const State &glState, |
| + bool isCallValid, |
| + GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + RenderbufferID renderbufferPacked); |
| + |
| // Parameter Captures |
| |
| void CaptureDeletePerfMonitorsAMD_monitors(const State &glState, |
| diff --git a/src/libANGLE/features.h b/src/libANGLE/features.h |
| index a6fe076c72d043dba3fc347bf020ebf8ec895f51..add46e99c91d19bbd790d2de0d8768b8953d633e 100644 |
| --- a/src/libANGLE/features.h |
| +++ b/src/libANGLE/features.h |
| @@ -44,4 +44,11 @@ |
| # define ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION 1 |
| #endif |
| |
| +// Lose context on Metal command queue error |
| +// ENABLED check Metal command buffer status on completion for error and lose context on error. |
| +// DISABLED Metal backed contexts are never lost. |
| +#if !defined(ANGLE_METAL_LOSE_CONTEXT_ON_ERROR) |
| +# define ANGLE_METAL_LOSE_CONTEXT_ON_ERROR ANGLE_ENABLED |
| +#endif |
| + |
| #endif // LIBANGLE_FEATURES_H_ |
| diff --git a/src/libANGLE/formatutils.cpp b/src/libANGLE/formatutils.cpp |
| index 35d19e35782b5ac50ca1e0fe77948ec3f4384cd0..b7d3f5d733d134f6579f489f0f55e3d4603f9605 100644 |
| --- a/src/libANGLE/formatutils.cpp |
| +++ b/src/libANGLE/formatutils.cpp |
| @@ -571,6 +571,7 @@ static GLenum EquivalentBlitInternalFormat(GLenum internalformat) |
| // multisampled RGBA8 renderbuffer to a BGRA8 texture). This could |
| // be expanded and/or autogenerated if that is found necessary. |
| if (internalformat == GL_BGRA_EXT || internalformat == GL_BGRA8_EXT || |
| + internalformat == GL_SRGB8_ALPHA8_EXT || internalformat == GL_BGRA8_EXT || |
| internalformat == GL_BGRA8_SRGB_ANGLEX) |
| { |
| return GL_RGBA8; |
| diff --git a/src/libANGLE/formatutils.h b/src/libANGLE/formatutils.h |
| index 1b3ae4ceb7001cfd84ec7d1684bfe1360e46af1e..2b0bc30927be422e300a1e041dbe6efdc7672d6a 100644 |
| --- a/src/libANGLE/formatutils.h |
| +++ b/src/libANGLE/formatutils.h |
| @@ -180,7 +180,6 @@ struct InternalFormat |
| |
| [[nodiscard]] bool computeBufferRowLength(uint32_t width, uint32_t *resultOut) const; |
| [[nodiscard]] bool computeBufferImageHeight(uint32_t height, uint32_t *resultOut) const; |
| - |
| [[nodiscard]] bool computeRowPitch(GLenum formatType, |
| GLsizei width, |
| GLint alignment, |
| diff --git a/src/libANGLE/gles_extensions_autogen.cpp b/src/libANGLE/gles_extensions_autogen.cpp |
| index 60b135494f77cd4628e2165fff4d3881b1f96037..843ebec51081007ae9d22fe0b80755df8f61d5b5 100644 |
| --- a/src/libANGLE/gles_extensions_autogen.cpp |
| +++ b/src/libANGLE/gles_extensions_autogen.cpp |
| @@ -243,6 +243,7 @@ const ExtensionInfoMap &GetExtensionInfoMap() |
| map["GL_CHROMIUM_copy_compressed_texture"] = esOnlyExtension(&Extensions::copyCompressedTextureCHROMIUM); |
| map["GL_CHROMIUM_copy_texture"] = esOnlyExtension(&Extensions::copyTextureCHROMIUM); |
| map["GL_ANGLE_copy_texture_3d"] = enableableExtension(&Extensions::copyTexture3dANGLE); |
| + map["GL_WEBKIT_explicit_resolve_target"] = enableableExtension(&Extensions::explicitResolveTargetWEBKIT); |
| map["GL_CHROMIUM_framebuffer_mixed_samples"] = esOnlyExtension(&Extensions::framebufferMixedSamplesCHROMIUM); |
| map["GL_ANGLE_framebuffer_multisample"] = enableableExtension(&Extensions::framebufferMultisampleANGLE); |
| map["GL_ANGLE_get_image"] = enableableExtension(&Extensions::getImageANGLE); |
| @@ -277,6 +278,7 @@ const ExtensionInfoMap &GetExtensionInfoMap() |
| map["GL_ANGLE_texture_compression_dxt5"] = enableableExtension(&Extensions::textureCompressionDxt5ANGLE); |
| map["GL_ANGLE_texture_multisample"] = enableableExtension(&Extensions::textureMultisampleANGLE); |
| map["GL_ANGLE_texture_rectangle"] = enableableExtension(&Extensions::textureRectangleANGLE); |
| + map["GL_ANGLE_variable_rasterization_rate_metal"] = enableableExtension(&Extensions::variableRasterizationRateMetalANGLE); |
| map["GL_ANGLE_vulkan_image"] = enableableExtension(&Extensions::vulkanImageANGLE); |
| map["GL_ANGLE_webgl_compatibility"] = esOnlyExtension(&Extensions::webglCompatibilityANGLE); |
| map["GL_ANGLE_yuv_internal_format"] = enableableExtension(&Extensions::yuvInternalFormatANGLE); |
| diff --git a/src/libANGLE/gles_extensions_autogen.h b/src/libANGLE/gles_extensions_autogen.h |
| index 318a292bfd867d7659b51d15ba05e759c058cc13..209d0033b054a88a26e248c6e16b76b4d1f775d7 100644 |
| --- a/src/libANGLE/gles_extensions_autogen.h |
| +++ b/src/libANGLE/gles_extensions_autogen.h |
| @@ -708,6 +708,9 @@ struct Extensions |
| // GL_ANGLE_copy_texture_3d |
| bool copyTexture3dANGLE = false; |
| |
| + // GL_WEBKIT_explicit_resolve_target |
| + bool explicitResolveTargetWEBKIT = false; |
| + |
| // GL_CHROMIUM_framebuffer_mixed_samples |
| bool framebufferMixedSamplesCHROMIUM = false; |
| |
| @@ -810,6 +813,9 @@ struct Extensions |
| // GL_ANGLE_texture_rectangle |
| bool textureRectangleANGLE = false; |
| |
| + // GL_ANGLE_variable_rasterization_rate_metal |
| + bool variableRasterizationRateMetalANGLE = false; |
| + |
| // GL_ANGLE_vulkan_image |
| bool vulkanImageANGLE = false; |
| |
| diff --git a/src/libANGLE/renderer/ContextImpl.cpp b/src/libANGLE/renderer/ContextImpl.cpp |
| index ec521e0712beede891dd75d5ef454e08fb5da2a5..c2c1b0d00175bb8fc3e030b1709ef212700a6c4a 100644 |
| --- a/src/libANGLE/renderer/ContextImpl.cpp |
| +++ b/src/libANGLE/renderer/ContextImpl.cpp |
| @@ -116,4 +116,13 @@ const angle::ShadingRateMap &ContextImpl::getSupportedFragmentShadingRateEXTSamp |
| static angle::ShadingRateMap empty; |
| return empty; |
| } |
| + |
| +angle::Result ContextImpl::bindMetalRasterizationRateMap(gl::Context *, |
| + RenderbufferImpl *renderbuffer, |
| + GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + UNREACHABLE(); |
| + return angle::Result::Stop; |
| +} |
| + |
| } // namespace rx |
| diff --git a/src/libANGLE/renderer/ContextImpl.h b/src/libANGLE/renderer/ContextImpl.h |
| index 0ebad533292ff09cd7bc8a1f915ab58b00b78bf5..39a4046fd3755b62ac3809a41e342e23a450e273 100644 |
| --- a/src/libANGLE/renderer/ContextImpl.h |
| +++ b/src/libANGLE/renderer/ContextImpl.h |
| @@ -280,6 +280,11 @@ class ContextImpl : public GLImplFactory |
| virtual const angle::PerfMonitorCounterGroupsInfo &getPerfMonitorCountersInfo() const; |
| virtual const angle::PerfMonitorCounterGroups &getPerfMonitorCounters(); |
| |
| + // GL_ANGLE_variable_rasterization_rate_metal |
| + virtual angle::Result bindMetalRasterizationRateMap(gl::Context *, |
| + RenderbufferImpl *renderbuffer, |
| + GLMTLRasterizationRateMapANGLE map); |
| + |
| protected: |
| const gl::State &mState; |
| gl::MemoryProgramCache *mMemoryProgramCache; |
| diff --git a/src/libANGLE/renderer/DisplayImpl.cpp b/src/libANGLE/renderer/DisplayImpl.cpp |
| index 8b4573f4d9dccfbeaccedfb8f6f07fb1ad1dc3f3..bf46443c7ed5449ffb31348a433e9c89ff99511c 100644 |
| --- a/src/libANGLE/renderer/DisplayImpl.cpp |
| +++ b/src/libANGLE/renderer/DisplayImpl.cpp |
| @@ -102,7 +102,7 @@ egl::Error DisplayImpl::validatePixmap(const egl::Config *config, |
| const egl::AttributeMap &attributes) const |
| { |
| UNREACHABLE(); |
| - return egl::Error(EGL_BAD_DISPLAY, "DisplayImpl::valdiatePixmap unimplemented."); |
| + return egl::Error(EGL_BAD_DISPLAY, "DisplayImpl::validatePixmap unimplemented."); |
| } |
| |
| const egl::Caps &DisplayImpl::getCaps() const |
| diff --git a/src/libANGLE/renderer/gl/FunctionsGL.cpp b/src/libANGLE/renderer/gl/FunctionsGL.cpp |
| index c85ef6270cb1f10b6e17c179b0e5195042b4a039..11de2386287c32d94a8c79c0ea2ee28f990e05fd 100644 |
| --- a/src/libANGLE/renderer/gl/FunctionsGL.cpp |
| +++ b/src/libANGLE/renderer/gl/FunctionsGL.cpp |
| @@ -55,7 +55,11 @@ static std::vector<std::string> GetIndexedExtensions(PFNGLGETINTEGERVPROC getInt |
| |
| for (GLint i = 0; i < numExtensions; i++) |
| { |
| - result.push_back(reinterpret_cast<const char *>(getStringIFunction(GL_EXTENSIONS, i))); |
| + if (const char *extensionString = |
| + reinterpret_cast<const char *>(getStringIFunction(GL_EXTENSIONS, i))) |
| + { |
| + result.push_back(extensionString); |
| + } |
| } |
| |
| return result; |
| diff --git a/src/libANGLE/renderer/gl/StateManagerGL.cpp b/src/libANGLE/renderer/gl/StateManagerGL.cpp |
| index 52b4f03badd78ea7db9a389e0c7385093ef711e8..8ab185343792701ceb45cc4bf086d3ee1b9e8168 100644 |
| --- a/src/libANGLE/renderer/gl/StateManagerGL.cpp |
| +++ b/src/libANGLE/renderer/gl/StateManagerGL.cpp |
| @@ -2507,6 +2507,9 @@ angle::Result StateManagerGL::syncState(const gl::Context *context, |
| break; |
| case gl::state::EXTENDED_DIRTY_BIT_FETCH_PER_SAMPLE_ENABLED: |
| break; |
| + case gl::state::EXTENDED_DIRTY_BIT_VARIABLE_RASTERIZATION_RATE: |
| + // Unimplemented extensions. |
| + break; |
| default: |
| UNREACHABLE(); |
| break; |
| diff --git a/src/libANGLE/renderer/metal/BUILD.gn b/src/libANGLE/renderer/metal/BUILD.gn |
| index 779b2f4fe32a213e83ac9eac653383b60984c578..e2f0207067ffbdb7c8f4fc37ae972d628615e426 100644 |
| --- a/src/libANGLE/renderer/metal/BUILD.gn |
| +++ b/src/libANGLE/renderer/metal/BUILD.gn |
| @@ -15,7 +15,10 @@ assert(is_mac || is_ios) |
| assert(angle_enable_metal) |
| |
| config("angle_metal_backend_config") { |
| - defines = [ "ANGLE_ENABLE_METAL" ] |
| + defines = [ |
| + "ANGLE_ENABLE_METAL", |
| + "ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED=1", |
| + ] |
| ldflags = [ |
| "-weak_framework", |
| "Metal", |
| diff --git a/src/libANGLE/renderer/metal/BufferMtl.mm b/src/libANGLE/renderer/metal/BufferMtl.mm |
| index 1f56d3ddabe1c8d6534f20d3393f5d480749dec0..2f5fd3a7995a552b5d7ba4b7dd6dc5e9686c4b3c 100644 |
| --- a/src/libANGLE/renderer/metal/BufferMtl.mm |
| +++ b/src/libANGLE/renderer/metal/BufferMtl.mm |
| @@ -340,12 +340,13 @@ void BufferMtl::onDataChanged() |
| |
| angle::Span<const uint8_t> BufferMtl::getBufferDataReadOnly(ContextMtl *contextMtl, size_t offset) |
| { |
| + size_t length = size() - offset; |
| if (mShadowCopy.size() == 0) |
| { |
| // Don't need shadow copy in this case, use the buffer directly |
| - return mBuffer->mapReadOnly(contextMtl, offset); |
| + return mBuffer->mapReadOnly(contextMtl, offset, length); |
| } |
| - return syncAndObtainShadowCopy(contextMtl, offset); |
| + return syncAndObtainShadowCopy(contextMtl, offset, length); |
| } |
| |
| bool BufferMtl::clientShadowCopyDataNeedSync(ContextMtl *contextMtl) |
| @@ -429,7 +430,7 @@ ConversionBufferMtl *BufferMtl::getUniformConversionBuffer(ContextMtl *context, |
| { |
| if (buffer.offset.second <= offset.second && |
| (offset.second - buffer.offset.second) % buffer.uniformBufferBlockSize == 0) |
| - return &buffer; |
| + return static_cast<ConversionBufferMtl *>(&buffer); |
| } |
| } |
| |
| diff --git a/src/libANGLE/renderer/metal/ContextMtl.h b/src/libANGLE/renderer/metal/ContextMtl.h |
| index e9ca3758ab9e782a1c7e1020e16a7b075de660c2..41553c65283aa530da36230b73329d9643de58aa 100644 |
| --- a/src/libANGLE/renderer/metal/ContextMtl.h |
| +++ b/src/libANGLE/renderer/metal/ContextMtl.h |
| @@ -273,6 +273,10 @@ class ContextMtl : public ContextImpl, public mtl::Context |
| angle::Result memoryBarrier(const gl::Context *context, GLbitfield barriers) override; |
| angle::Result memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers) override; |
| |
| + angle::Result bindMetalRasterizationRateMap(gl::Context *context, |
| + RenderbufferImpl *renderbuffer, |
| + GLMTLRasterizationRateMapANGLE map) override; |
| + |
| // override mtl::ErrorHandler |
| void handleError(GLenum error, |
| const char *message, |
| @@ -418,6 +422,7 @@ class ContextMtl : public ContextImpl, public mtl::Context |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| GLsizei instanceCount, |
| + GLuint baseInstance, |
| gl::DrawElementsType indexTypeOrNone, |
| const void *indices, |
| bool xfbPass, |
| @@ -427,6 +432,7 @@ class ContextMtl : public ContextImpl, public mtl::Context |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| GLsizei instanceCount, |
| + GLuint baseInstance, |
| gl::DrawElementsType indexTypeOrNone, |
| const void *indices, |
| bool xfbPass, |
| @@ -554,6 +560,7 @@ class ContextMtl : public ContextImpl, public mtl::Context |
| DIRTY_BIT_RENDER_PIPELINE, |
| DIRTY_BIT_UNIFORM_BUFFERS_BINDING, |
| DIRTY_BIT_RASTERIZER_DISCARD, |
| + DIRTY_BIT_VARIABLE_RASTERIZATION_RATE, |
| |
| DIRTY_BIT_INVALID, |
| DIRTY_BIT_MAX = DIRTY_BIT_INVALID, |
| @@ -647,6 +654,9 @@ class ContextMtl : public ContextImpl, public mtl::Context |
| IncompleteTextureSet mIncompleteTextures; |
| ProvokingVertexHelper mProvokingVertexHelper; |
| |
| + angle::ObjCPtr<id<MTLRasterizationRateMap>> mRasterizationRateMap; |
| + id<MTLTexture> mRasterizationRateMapTexture; |
| + |
| mtl::ContextDevice mContextDevice; |
| }; |
| |
| diff --git a/src/libANGLE/renderer/metal/ContextMtl.mm b/src/libANGLE/renderer/metal/ContextMtl.mm |
| index bd0acbf89cace2fcc92bfd7f7e9bd2efcd67eded..644b213beee9b8f5fdeec8c8daf86b8016369c33 100644 |
| --- a/src/libANGLE/renderer/metal/ContextMtl.mm |
| +++ b/src/libANGLE/renderer/metal/ContextMtl.mm |
| @@ -243,6 +243,8 @@ void ContextMtl::onDestroy(const gl::Context *context) |
| mIncompleteTextures.onDestroy(context); |
| mProvokingVertexHelper.onDestroy(this); |
| mDummyXFBRenderTexture = nullptr; |
| + mRasterizationRateMap.reset(); |
| + mRasterizationRateMapTexture = nil; |
| |
| mContextDevice.reset(); |
| } |
| @@ -314,8 +316,9 @@ angle::Result ContextMtl::drawTriFanArraysWithBaseVertex(const gl::Context *cont |
| |
| ASSERT(!getState().isTransformFeedbackActiveUnpaused()); |
| bool isNoOp = false; |
| - ANGLE_TRY(setupDraw(context, first, count, instances, gl::DrawElementsType::InvalidEnum, |
| - reinterpret_cast<const void *>(0), false, &isNoOp)); |
| + ANGLE_TRY(setupDraw(context, first, count, instances, baseInstance, |
| + gl::DrawElementsType::InvalidEnum, reinterpret_cast<const void *>(0), false, |
| + &isNoOp)); |
| if (!isNoOp) |
| { |
| // Draw with the zero starting index buffer, shift the vertex index using baseVertex |
| @@ -345,7 +348,7 @@ angle::Result ContextMtl::drawTriFanArraysLegacy(const gl::Context *context, |
| |
| ASSERT(!getState().isTransformFeedbackActiveUnpaused()); |
| bool isNoOp = false; |
| - ANGLE_TRY(setupDraw(context, first, count, instances, gl::DrawElementsType::InvalidEnum, |
| + ANGLE_TRY(setupDraw(context, first, count, instances, 0, gl::DrawElementsType::InvalidEnum, |
| reinterpret_cast<const void *>(0), false, &isNoOp)); |
| if (!isNoOp) |
| { |
| @@ -409,8 +412,8 @@ angle::Result ContextMtl::drawLineLoopArrays(const gl::Context *context, |
| |
| ASSERT(!getState().isTransformFeedbackActiveUnpaused()); |
| bool isNoOp = false; |
| - ANGLE_TRY(setupDraw(context, first, count, instances, gl::DrawElementsType::InvalidEnum, |
| - nullptr, false, &isNoOp)); |
| + ANGLE_TRY(setupDraw(context, first, count, instances, baseInstance, |
| + gl::DrawElementsType::InvalidEnum, nullptr, false, &isNoOp)); |
| if (!isNoOp) |
| { |
| if (baseInstance == 0) |
| @@ -479,8 +482,8 @@ angle::Result ContextMtl::drawArraysImpl(const gl::Context *context, |
| #define DRAW_GENERIC_ARRAY(xfbPass) \ |
| { \ |
| bool isNoOp = false; \ |
| - ANGLE_TRY(setupDraw(context, first, count, instances, gl::DrawElementsType::InvalidEnum, \ |
| - nullptr, xfbPass, &isNoOp)); \ |
| + ANGLE_TRY(setupDraw(context, first, count, instances, baseInstance, \ |
| + gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp)); \ |
| if (!isNoOp) \ |
| { \ |
| \ |
| @@ -569,7 +572,8 @@ angle::Result ContextMtl::drawTriFanElements(const gl::Context *context, |
| |
| ANGLE_TRY(mTriFanIndexBuffer.commit(this)); |
| bool isNoOp = false; |
| - ANGLE_TRY(setupDraw(context, 0, count, instances, type, indices, false, &isNoOp)); |
| + ANGLE_TRY( |
| + setupDraw(context, 0, count, instances, baseInstance, type, indices, false, &isNoOp)); |
| if (!isNoOp && genIndicesCount > 0) |
| { |
| if (baseVertex == 0 && baseInstance == 0) |
| @@ -640,7 +644,8 @@ angle::Result ContextMtl::drawLineLoopElements(const gl::Context *context, |
| |
| ANGLE_TRY(mLineLoopIndexBuffer.commit(this)); |
| bool isNoOp = false; |
| - ANGLE_TRY(setupDraw(context, 0, count, instances, type, indices, false, &isNoOp)); |
| + ANGLE_TRY( |
| + setupDraw(context, 0, count, instances, baseInstance, type, indices, false, &isNoOp)); |
| if (!isNoOp && genIndicesCount > 0) |
| { |
| if (baseVertex == 0 && baseInstance == 0) |
| @@ -691,8 +696,8 @@ angle::Result ContextMtl::drawArraysProvokingVertexImpl(const gl::Context *conte |
| if (xfbPass) \ |
| { \ |
| bool isNoOp = false; \ |
| - ANGLE_TRY(setupDraw(context, first, count, instances, gl::DrawElementsType::InvalidEnum, \ |
| - nullptr, xfbPass, &isNoOp)); \ |
| + ANGLE_TRY(setupDraw(context, first, count, instances, baseInstance, \ |
| + gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp)); \ |
| if (!isNoOp) \ |
| { \ |
| MTLPrimitiveType mtlType = mtl::GetPrimitiveType(mode); \ |
| @@ -718,8 +723,8 @@ angle::Result ContextMtl::drawArraysProvokingVertexImpl(const gl::Context *conte |
| else \ |
| { \ |
| bool isNoOp = false; \ |
| - ANGLE_TRY(setupDraw(context, first, count, instances, gl::DrawElementsType::InvalidEnum, \ |
| - nullptr, xfbPass, &isNoOp)); \ |
| + ANGLE_TRY(setupDraw(context, first, count, instances, baseInstance, \ |
| + gl::DrawElementsType::InvalidEnum, nullptr, xfbPass, &isNoOp)); \ |
| \ |
| if (!isNoOp) \ |
| { \ |
| @@ -789,7 +794,8 @@ angle::Result ContextMtl::drawElementsImpl(const gl::Context *context, |
| mState.isPrimitiveRestartEnabled(), &newMode, &drawCommands, &idxBuffer, &idxBufferType)); |
| |
| bool isNoOp = false; |
| - ANGLE_TRY(setupDraw(context, 0, count, instances, type, indices, false, &isNoOp)); |
| + ANGLE_TRY( |
| + setupDraw(context, 0, count, instances, baseInstance, type, indices, false, &isNoOp)); |
| if (!isNoOp) |
| { |
| MTLPrimitiveType mtlType = mtl::GetPrimitiveType(newMode); |
| @@ -1035,6 +1041,13 @@ angle::Result ContextMtl::multiDrawElementsInstancedBaseVertexBaseInstance( |
| // Device loss |
| gl::GraphicsResetStatus ContextMtl::getResetStatus() |
| { |
| +#if ANGLE_METAL_LOSE_CONTEXT_ON_ERROR == ANGLE_ENABLED |
| + if (cmdQueue().isDeviceLost()) |
| + { |
| + return gl::GraphicsResetStatus::UnknownContextReset; |
| + } |
| +#endif |
| + |
| return gl::GraphicsResetStatus::NoError; |
| } |
| |
| @@ -1373,6 +1386,9 @@ void ContextMtl::updateExtendedState(const gl::State &glState, |
| case gl::state::EXTENDED_DIRTY_BIT_POLYGON_OFFSET_LINE_ENABLED: |
| mDirtyBits.set(DIRTY_BIT_DEPTH_BIAS); |
| break; |
| + case gl::state::EXTENDED_DIRTY_BIT_VARIABLE_RASTERIZATION_RATE: |
| + mDirtyBits.set(DIRTY_BIT_VARIABLE_RASTERIZATION_RATE); |
| + break; |
| default: |
| break; |
| } |
| @@ -1628,6 +1644,37 @@ angle::Result ContextMtl::memoryBarrierByRegion(const gl::Context *context, GLbi |
| return angle::Result::Stop; |
| } |
| |
| +angle::Result ContextMtl::bindMetalRasterizationRateMap(gl::Context *context, |
| + RenderbufferImpl *renderbuffer, |
| + GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + id<MTLRasterizationRateMap> rateMap = (__bridge id<MTLRasterizationRateMap>)(map); |
| + if (rateMap && rateMap.device != mContextDevice.get()) |
| + { |
| + return angle::Result::Stop; |
| + } |
| + |
| + if (auto *metalRenderbuffer = static_cast<RenderbufferMtl *>(renderbuffer)) |
| + { |
| + FramebufferAttachmentRenderTarget *rtOut = nullptr; |
| + gl::OwnImageIndex index(gl::ImageIndex::Make2D(0)); |
| + GLenum binding = 0; |
| + if (angle::Result::Continue == |
| + metalRenderbuffer->getAttachmentRenderTarget(context, binding, index, 1, &rtOut)) |
| + { |
| + if (auto *renderTargetMetal = static_cast<RenderTargetMtl *>(rtOut)) |
| + { |
| + mtl::RenderPassAttachmentDesc desc; |
| + renderTargetMetal->toRenderPassAttachmentDesc(&desc); |
| + mRasterizationRateMapTexture = desc.texture.get()->get(); |
| + } |
| + } |
| + } |
| + |
| + mRasterizationRateMap = std::move(rateMap); |
| + return angle::Result::Continue; |
| +} |
| + |
| // override mtl::ErrorHandler |
| void ContextMtl::handleError(GLenum glErrorCode, |
| const char *message, |
| @@ -1891,16 +1938,22 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::Re |
| mDirtyBits.set(); |
| |
| const mtl::ContextDevice &metalDevice = getMetalDevice(); |
| - if (mtl::DeviceHasMaximumRenderTargetSize(metalDevice)) |
| + const std::optional<NSUInteger> maxSize = |
| + mtl::GetMaxRenderPassColorSizeBytes(getDisplay()->getFeatures(), metalDevice); |
| + if (maxSize) |
| { |
| - NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice); |
| NSUInteger renderTargetSize = |
| ComputeTotalSizeUsedForMTLRenderPassDescriptor(desc, this, metalDevice); |
| - if (renderTargetSize > maxSize) |
| + if (renderTargetSize > *maxSize) |
| { |
| + // Unreachable: FramebufferMtl::checkStatus rejects color-attachment |
| + // configurations whose total byte size exceeds this device's |
| + // budget, so the encoder-time check is defensive only. |
| + UNREACHABLE(); |
| std::stringstream errorStream; |
| errorStream << "This set of render targets requires " << renderTargetSize |
| - << " bytes of pixel storage. This device supports " << maxSize << " bytes."; |
| + << " bytes of pixel storage. This device supports " << *maxSize |
| + << " bytes."; |
| handleError(GL_INVALID_OPERATION, errorStream.str().c_str(), __FILE__, ANGLE_FUNCTION, |
| __LINE__); |
| return nullptr; |
| @@ -2432,13 +2485,14 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context, |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| GLsizei instances, |
| + GLuint baseInstance, |
| gl::DrawElementsType indexTypeOrNone, |
| const void *indices, |
| bool xfbPass, |
| bool *isNoOp) |
| { |
| - ANGLE_TRY(setupDrawImpl(context, firstVertex, vertexOrIndexCount, instances, indexTypeOrNone, |
| - indices, xfbPass, isNoOp)); |
| + ANGLE_TRY(setupDrawImpl(context, firstVertex, vertexOrIndexCount, instances, baseInstance, |
| + indexTypeOrNone, indices, xfbPass, isNoOp)); |
| if (*isNoOp) |
| { |
| return angle::Result::Continue; |
| @@ -2449,7 +2503,7 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context, |
| // pass state. This would happen for example when there is no more space in the uniform |
| // buffers in the uniform buffer pool. The rendering would be flushed to free the uniform |
| // buffer memory for new usage. In this case, re-run the setup. |
| - ANGLE_TRY(setupDrawImpl(context, firstVertex, vertexOrIndexCount, instances, |
| + ANGLE_TRY(setupDrawImpl(context, firstVertex, vertexOrIndexCount, instances, baseInstance, |
| indexTypeOrNone, indices, xfbPass, isNoOp)); |
| |
| if (*isNoOp) |
| @@ -2457,8 +2511,22 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context, |
| return checkCommandBufferError(); |
| } |
| // Setup with flushed state should either produce a working encoder or fail with an error |
| - // result. |
| - ASSERT(mRenderEncoder.valid()); |
| + // result. if that's not the case, something's gone seriously wrong. Try to |
| + // recover from the error by bailing out of the draw call, and finishing the command buffer. |
| + // This will result in an unfinished / corrupted draw, but will avoid a browser/GPU process |
| + // crash. |
| + if (ANGLE_UNLIKELY(!mRenderEncoder.valid() || !mRenderEncoder.hasPipelineState())) |
| + { |
| + // Completely flush the command buffer, waiting synchronously. |
| + flushCommandBuffer(mtl::WaitUntilFinished); |
| + // Invalidate all state |
| + invalidateState(context); |
| + // Return fail, and drop the draw call. This is |
| + // a worst case scenario. If in a debug roots situation, |
| + // we should try to catch the call stack. |
| + ERR() << "Draw call is unusable - please report a bug on bugs.webkit.org"; |
| + return angle::Result::Stop; |
| + } |
| } |
| return angle::Result::Continue; |
| } |
| @@ -2467,6 +2535,7 @@ angle::Result ContextMtl::setupDrawImpl(const gl::Context *context, |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| GLsizei instances, |
| + GLuint baseInstance, |
| gl::DrawElementsType indexTypeOrNone, |
| const void *indices, |
| bool xfbPass, |
| @@ -2480,7 +2549,8 @@ angle::Result ContextMtl::setupDrawImpl(const gl::Context *context, |
| if (context->hasAnyActiveClientAttrib()) |
| { |
| ANGLE_TRY(mVertexArray->updateClientAttribs(context, firstVertex, vertexOrIndexCount, |
| - instanceCount, indexTypeOrNone, indices)); |
| + instanceCount, baseInstance, indexTypeOrNone, |
| + indices)); |
| } |
| |
| // This must be called before render command encoder is started. |
| @@ -2566,10 +2636,14 @@ angle::Result ContextMtl::setupDrawImpl(const gl::Context *context, |
| mState.getBlendColor().blue, mState.getBlendColor().alpha); |
| break; |
| case DIRTY_BIT_VIEWPORT: |
| - mRenderEncoder.setViewport(mViewport); |
| + mRenderEncoder.setViewport( |
| + mViewport, mRenderEncoder.rasterizationRateMapForPass( |
| + mRasterizationRateMap, mRasterizationRateMapTexture)); |
| break; |
| case DIRTY_BIT_SCISSOR: |
| - mRenderEncoder.setScissorRect(mScissorRect); |
| + mRenderEncoder.setScissorRect( |
| + mScissorRect, mRenderEncoder.rasterizationRateMapForPass( |
| + mRasterizationRateMap, mRasterizationRateMapTexture)); |
| break; |
| case DIRTY_BIT_DRAW_FRAMEBUFFER: |
| // Already handled. |
| @@ -2594,6 +2668,15 @@ angle::Result ContextMtl::setupDrawImpl(const gl::Context *context, |
| case DIRTY_BIT_RASTERIZER_DISCARD: |
| // Already handled. |
| break; |
| + case DIRTY_BIT_VARIABLE_RASTERIZATION_RATE: |
| + if (getState().privateState().isVariableRasterizationRateEnabled() && |
| + mRasterizationRateMap) |
| + { |
| + mRenderEncoder.setRasterizationRateMap( |
| + mRenderEncoder.rasterizationRateMapForPass(mRasterizationRateMap, |
| + mRasterizationRateMapTexture)); |
| + } |
| + break; |
| default: |
| UNREACHABLE(); |
| break; |
| diff --git a/src/libANGLE/renderer/metal/DisplayMtl.h b/src/libANGLE/renderer/metal/DisplayMtl.h |
| index 6901918d85ad1c32049d536950195d02262e8e1c..a1fdd8065d8e76b55b32e13ce72cc5f7aa711bfb 100644 |
| --- a/src/libANGLE/renderer/metal/DisplayMtl.h |
| +++ b/src/libANGLE/renderer/metal/DisplayMtl.h |
| @@ -140,6 +140,7 @@ class DisplayMtl : public DisplayImpl |
| bool supportsDepth24Stencil8PixelFormat() const; |
| bool supports32BitFloatFiltering() const; |
| bool supportsBCTextureCompression() const; |
| + bool supportsVariableRasterizationRate() const; |
| bool isAMD() const; |
| bool isAMDBronzeDriver() const; |
| bool isAMDFireProDevice() const; |
| @@ -154,7 +155,6 @@ class DisplayMtl : public DisplayImpl |
| mtl::RenderUtils &getUtils() { return *mUtils; } |
| mtl::StateCache &getStateCache() { return mStateCache; } |
| mtl::LibraryCache &getLibraryCache() { return mLibraryCache; } |
| - uint32_t getMaxColorTargetBits() { return mMaxColorTargetBits; } |
| bool hasFragmentMemoryBarriers() const { return mHasFragmentMemoryBarriers; } |
| |
| id<MTLLibrary> getDefaultShadersLib(); |
| @@ -218,7 +218,6 @@ class DisplayMtl : public DisplayImpl |
| mutable gl::Caps mNativeCaps; |
| mutable gl::Limitations mNativeLimitations; |
| mutable ShPixelLocalStorageOptions mNativePLSOptions; |
| - mutable uint32_t mMaxColorTargetBits = 0; |
| mutable bool mHasFragmentMemoryBarriers; |
| |
| angle::FeaturesMtl mFeatures; |
| diff --git a/src/libANGLE/renderer/metal/DisplayMtl.mm b/src/libANGLE/renderer/metal/DisplayMtl.mm |
| index ac0d8a3425cb8b68334e16d24db59204e0bdd432..6fa6bbabe4186527c62fbc004fd902152b7b9fc0 100644 |
| --- a/src/libANGLE/renderer/metal/DisplayMtl.mm |
| +++ b/src/libANGLE/renderer/metal/DisplayMtl.mm |
| @@ -180,12 +180,22 @@ void DisplayMtl::terminate() |
| |
| bool DisplayMtl::testDeviceLost() |
| { |
| +#if ANGLE_METAL_LOSE_CONTEXT_ON_ERROR == ANGLE_ENABLED |
| + return mCmdQueue.isDeviceLost(); |
| +#else |
| return false; |
| +#endif |
| } |
| |
| egl::Error DisplayMtl::restoreLostDevice(const egl::Display *display) |
| { |
| +#if ANGLE_METAL_LOSE_CONTEXT_ON_ERROR == ANGLE_ENABLED |
| + // A Metal device cannot be restored, the entire context would have to be |
| + // re-created along with any other EGL objects that reference it. |
| + return egl::Error(EGL_BAD_DISPLAY); |
| +#else |
| return egl::NoError(); |
| +#endif |
| } |
| |
| std::string DisplayMtl::getRendererDescription() |
| @@ -236,6 +246,10 @@ angle::ObjCPtr<id<MTLDevice>> DisplayMtl::getMetalDeviceMatchingAttribute( |
| { |
| #if TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| auto deviceList = angle::adoptObjCPtr(MTLCopyAllDevices()); |
| + if ([deviceList count] == 1) |
| + { |
| + return deviceList[0]; |
| + } |
| |
| EGLAttrib high = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0); |
| EGLAttrib low = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0); |
| @@ -782,25 +796,6 @@ void DisplayMtl::ensureCapsInitialized() const |
| mNativeCaps.maxViewportWidth = mNativeCaps.max2DTextureSize; |
| mNativeCaps.maxViewportHeight = mNativeCaps.max2DTextureSize; |
| |
| - bool isCatalyst = TARGET_OS_MACCATALYST; |
| - |
| - mMaxColorTargetBits = mtl::kMaxColorTargetBitsApple1To3; |
| - if (supportsMacGPUFamily(1) || isCatalyst) |
| - { |
| - mMaxColorTargetBits = mtl::kMaxColorTargetBitsMacAndCatalyst; |
| - } |
| - else if (supportsAppleGPUFamily(4)) |
| - { |
| - mMaxColorTargetBits = mtl::kMaxColorTargetBitsApple4Plus; |
| - } |
| - |
| - if (mFeatures.limitMaxColorTargetBitsForTesting.enabled) |
| - { |
| - // Set so we have enough for RGBA8 on every attachment |
| - // but not enough for RGBA32UI. |
| - mMaxColorTargetBits = mNativeCaps.maxColorAttachments * 32; |
| - } |
| - |
| // MSAA |
| mNativeCaps.maxSamples = mFormatTable.getMaxSamples(); |
| mNativeCaps.maxSampleMaskWords = 1; |
| @@ -1146,6 +1141,14 @@ void DisplayMtl::initializeExtensions() const |
| // qualifier on that hardware. |
| mNativePLSOptions.supportsNoncoherent = !supportsAppleGPUFamily(1); |
| |
| + // GL_ANGLE_variable_rasterization_rate_metal |
| + mNativeExtensions.variableRasterizationRateMetalANGLE = |
| + mFeatures.hasVariableRasterizationRate.enabled; |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + // GL_WEBKIT_explicit_resolve_target |
| + mNativeExtensions.explicitResolveTargetWEBKIT = true; |
| +#endif |
| + |
| // "The GPUs in Apple3 through Apple8 families only support memory barriers for compute command |
| // encoders, and for vertex-to-vertex and vertex-to-fragment stages of render command encoders." |
| mHasFragmentMemoryBarriers = !supportsAppleGPUFamily(3); |
| @@ -1211,6 +1214,8 @@ void DisplayMtl::initializeFeatures() |
| ANGLE_FEATURE_CONDITION((&mFeatures), hasExplicitMemBarrier, (isOSX || isCatalyst) && !isARM); |
| ANGLE_FEATURE_CONDITION((&mFeatures), hasDepthAutoResolve, supportsEitherGPUFamily(3, 2)); |
| ANGLE_FEATURE_CONDITION((&mFeatures), hasStencilAutoResolve, supportsEitherGPUFamily(5, 2)); |
| + ANGLE_FEATURE_CONDITION((&mFeatures), hasVariableRasterizationRate, |
| + supportsVariableRasterizationRate()); |
| ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve, |
| supportsEitherGPUFamily(3, 1)); |
| |
| @@ -1257,6 +1262,8 @@ void DisplayMtl::initializeFeatures() |
| ANGLE_FEATURE_CONDITION((&mFeatures), writeHelperSampleMask, supportsAppleGPUFamily(1)); |
| |
| ANGLE_FEATURE_CONDITION((&mFeatures), multisampleColorFormatShaderReadWorkaround, isAMD()); |
| + // At least for Radeon 5500M. See rdar://178796612. |
| + ANGLE_FEATURE_CONDITION((&mFeatures), clearMsaaRg16UnormWithDrawWorkaround, isAMD()); |
| ANGLE_FEATURE_CONDITION((&mFeatures), copyIOSurfaceToNonIOSurfaceForReadOptimization, |
| isIntel() || isAMD()); |
| ANGLE_FEATURE_CONDITION((&mFeatures), copyTextureToBufferForReadOptimization, isAMD()); |
| @@ -1394,6 +1401,17 @@ bool DisplayMtl::supportsDepth24Stencil8PixelFormat() const |
| return false; |
| #endif |
| } |
| + |
| +bool DisplayMtl::supportsVariableRasterizationRate() const |
| +{ |
| + if (@available(ios 13.0, macOS 10.15.4, macCatalyst 13.4, tvOS 16.0, *)) |
| + { |
| + return [mMetalDevice supportsRasterizationRateMapWithLayerCount:1]; |
| + } |
| + |
| + return false; |
| +} |
| + |
| bool DisplayMtl::isAMD() const |
| { |
| return angle::IsAMD(mMetalDeviceVendorId); |
| diff --git a/src/libANGLE/renderer/metal/FrameBufferMtl.h b/src/libANGLE/renderer/metal/FrameBufferMtl.h |
| index 1598346227a18112ce57ce308bee5ef738e6195a..731b1c1989d39bcb97832671066663f092a633db 100644 |
| --- a/src/libANGLE/renderer/metal/FrameBufferMtl.h |
| +++ b/src/libANGLE/renderer/metal/FrameBufferMtl.h |
| @@ -159,6 +159,9 @@ class FramebufferMtl : public FramebufferImpl |
| gl::DrawBufferMask clearColorBuffers, |
| const mtl::ClearRectParams &clearOpts); |
| |
| + bool needsRG16UnormMSAAClearWorkaround(const ContextMtl *contextMtl, |
| + gl::DrawBufferMask clearColorBuffers) const; |
| + |
| // Initialize load store options for a render pass's first start (i.e. not render pass resuming |
| // from interruptions such as those caused by a conversion compute pass) |
| void setLoadStoreActionOnRenderPassFirstStart(mtl::RenderPassAttachmentDesc *attachmentOut, |
| @@ -196,8 +199,6 @@ class FramebufferMtl : public FramebufferImpl |
| uint32_t dstBufferRowPitch, |
| const mtl::BufferRef *dstBuffer) const; |
| |
| - bool totalBitsUsedIsLessThanOrEqualToMaxBitsSupported(const gl::Context *context) const; |
| - |
| RenderTargetMtl *getColorReadRenderTargetNoCache(const gl::Context *context) const; |
| angle::Result prepareForUse(const gl::Context *context) const; |
| |
| @@ -210,6 +211,14 @@ class FramebufferMtl : public FramebufferImpl |
| angle::FixedVector<RenderTargetMtl *, mtl::kMaxRenderTargets> mColorRenderTargets; |
| RenderTargetMtl *mDepthRenderTarget = nullptr; |
| RenderTargetMtl *mStencilRenderTarget = nullptr; |
| + |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + // GL_WEBKIT_explicit_resolve_target |
| + angle::FixedVector<RenderTargetMtl *, mtl::kMaxRenderTargets> mColorResolveRenderTargets; |
| + RenderTargetMtl *mDepthResolveRenderTarget = nullptr; |
| + RenderTargetMtl *mStencilResolveRenderTarget = nullptr; |
| +#endif |
| + |
| mtl::RenderPassDesc mRenderPassDesc; |
| |
| const mtl::Format *mRenderPassFirstColorAttachmentFormat = nullptr; |
| diff --git a/src/libANGLE/renderer/metal/FrameBufferMtl.mm b/src/libANGLE/renderer/metal/FrameBufferMtl.mm |
| index d77d8ee90e85e54d8ab8e724ba846a4afc2813ed..0578719e678ccec0e232ea2bc040827c9d37c02c 100644 |
| --- a/src/libANGLE/renderer/metal/FrameBufferMtl.mm |
| +++ b/src/libANGLE/renderer/metal/FrameBufferMtl.mm |
| @@ -137,6 +137,9 @@ angle::Result Copy2DTextureSlice0Level0ToTempTexture(const gl::Context *context, |
| FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state, ContextMtl *context, bool flipY) |
| : FramebufferImpl(state), |
| mColorRenderTargets(context->getNativeCaps().maxColorAttachments, nullptr), |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + mColorResolveRenderTargets(context->getNativeCaps().maxColorAttachments, nullptr), |
| +#endif |
| mBackbuffer(nullptr), |
| mBackbufferFlipY(flipY) |
| { |
| @@ -164,6 +167,14 @@ void FramebufferMtl::reset() |
| } |
| mDepthRenderTarget = mStencilRenderTarget = nullptr; |
| |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + for (auto &rt : mColorResolveRenderTargets) |
| + { |
| + rt = nullptr; |
| + } |
| + mDepthResolveRenderTarget = mStencilResolveRenderTarget = nullptr; |
| +#endif |
| + |
| mRenderPassFirstColorAttachmentFormat = nullptr; |
| |
| mReadPixelBuffer = nullptr; |
| @@ -658,30 +669,18 @@ angle::Result FramebufferMtl::blitWithDraw(const gl::Context *context, |
| return angle::Result::Continue; |
| } |
| |
| -bool FramebufferMtl::totalBitsUsedIsLessThanOrEqualToMaxBitsSupported( |
| - const gl::Context *context) const |
| +gl::FramebufferStatus FramebufferMtl::checkStatus(const gl::Context *context) const |
| { |
| + // Read attachments from mState rather than the cached mColorRenderTargets: |
| + // returning true from shouldSyncStateBeforeCheckStatus() would force a full |
| + // state sync, but Framebuffer::syncState's "before-check-status" path is |
| + // only implemented for the GL backend. |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| + const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures(); |
| |
| - uint32_t bitsUsed = 0; |
| - for (const gl::FramebufferAttachment &attachment : mState.getColorAttachments()) |
| - { |
| - if (attachment.isAttached()) |
| - { |
| - bitsUsed += attachment.getRedSize() + attachment.getGreenSize() + |
| - attachment.getBlueSize() + attachment.getAlphaSize(); |
| - } |
| - } |
| - |
| - return bitsUsed <= contextMtl->getDisplay()->getMaxColorTargetBits(); |
| -} |
| - |
| -gl::FramebufferStatus FramebufferMtl::checkStatus(const gl::Context *context) const |
| -{ |
| if (mState.hasSeparateDepthAndStencilAttachments()) |
| { |
| - ContextMtl *contextMtl = mtl::GetImpl(context); |
| - if (!contextMtl->getDisplay()->getFeatures().allowSeparateDepthStencilBuffers.enabled) |
| + if (!features.allowSeparateDepthStencilBuffers.enabled) |
| { |
| return gl::FramebufferStatus::Incomplete( |
| GL_FRAMEBUFFER_UNSUPPORTED, |
| @@ -700,12 +699,37 @@ gl::FramebufferStatus FramebufferMtl::checkStatus(const gl::Context *context) co |
| } |
| } |
| |
| - if (!totalBitsUsedIsLessThanOrEqualToMaxBitsSupported(context)) |
| + const mtl::ContextDevice &device = contextMtl->getMetalDevice(); |
| + const std::optional<NSUInteger> maxSize = mtl::GetMaxRenderPassColorSizeBytes(features, device); |
| + if (maxSize) |
| + { |
| + const auto &colorAttachments = mState.getColorAttachments(); |
| + mtl::RenderPassDesc desc; |
| + for (size_t i = 0; i < colorAttachments.size(); ++i) |
| + { |
| + const gl::FramebufferAttachment &attachment = colorAttachments[i]; |
| + if (!attachment.isAttached()) |
| + { |
| + continue; |
| + } |
| + RenderTargetMtl *rt = nullptr; |
| + if (attachment.getRenderTarget(context, attachment.getRenderToTextureSamples(), &rt) == |
| + angle::Result::Stop || |
| + !rt || !rt->getTexture()) |
| + { |
| + return gl::FramebufferStatus::Incomplete( |
| + GL_FRAMEBUFFER_UNSUPPORTED, gl::err::kFramebufferIncompleteInternalError); |
| + } |
| + rt->toRenderPassAttachmentDesc(&desc.colorAttachments[i]); |
| + } |
| + if (mtl::ComputeTotalSizeUsedForMTLRenderPassDescriptor(desc, contextMtl, device) > |
| + *maxSize) |
| { |
| return gl::FramebufferStatus::Incomplete( |
| GL_FRAMEBUFFER_UNSUPPORTED, |
| gl::err::kFramebufferIncompleteColorBitsUsedExceedsMaxColorBitsSupported); |
| } |
| + } |
| |
| return gl::FramebufferStatus::Complete(); |
| } |
| @@ -926,6 +950,10 @@ angle::Result FramebufferMtl::ensureRenderPassStarted(const gl::Context *context |
| ASSERT(desc.equalIgnoreLoadStoreOptions(mRenderPassDesc)); |
| |
| encoder = contextMtl->getRenderPassCommandEncoder(desc); |
| + if (!encoder) |
| + { |
| + return angle::Result::Stop; |
| + } |
| mStartedRenderEncoderSerial = encoder->getSerial(); |
| |
| ANGLE_TRY(unresolveIfNeeded(context, encoder)); |
| @@ -966,7 +994,7 @@ void FramebufferMtl::setLoadStoreActionOnRenderPassFirstStart( |
| attachment.loadAction = MTLLoadActionLoad; |
| } |
| |
| - if (attachment.hasImplicitMSTexture()) |
| + if (attachment.hasResolveTexture()) |
| { |
| attachment.storeAction = MTLStoreActionStoreAndMultisampleResolve; |
| } |
| @@ -1033,22 +1061,47 @@ angle::Result FramebufferMtl::updateColorRenderTarget(const gl::Context *context |
| ASSERT(colorIndexGL < mColorRenderTargets.size()); |
| // Reset load store action |
| mRenderPassDesc.colorAttachments[colorIndexGL] = {}; |
| - return updateCachedRenderTarget(context, mState.getColorAttachment(colorIndexGL), |
| - &mColorRenderTargets[colorIndexGL]); |
| + ANGLE_TRY(updateCachedRenderTarget(context, mState.getColorAttachment(colorIndexGL), |
| + &mColorRenderTargets[colorIndexGL])); |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + if (mState.getColorResolveAttachment(colorIndexGL)) |
| + { |
| + ANGLE_TRY(updateCachedRenderTarget(context, mState.getColorResolveAttachment(colorIndexGL), |
| + &mColorResolveRenderTargets[colorIndexGL])); |
| + } |
| +#endif |
| + return angle::Result::Continue; |
| } |
| |
| angle::Result FramebufferMtl::updateDepthRenderTarget(const gl::Context *context) |
| { |
| // Reset load store action |
| mRenderPassDesc.depthAttachment = {}; |
| - return updateCachedRenderTarget(context, mState.getDepthAttachment(), &mDepthRenderTarget); |
| + ANGLE_TRY(updateCachedRenderTarget(context, mState.getDepthAttachment(), &mDepthRenderTarget)); |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + if (mState.getDepthResolveAttachment()) |
| + { |
| + ANGLE_TRY(updateCachedRenderTarget(context, mState.getDepthResolveAttachment(), |
| + &mDepthResolveRenderTarget)); |
| + } |
| +#endif |
| + return angle::Result::Continue; |
| } |
| |
| angle::Result FramebufferMtl::updateStencilRenderTarget(const gl::Context *context) |
| { |
| // Reset load store action |
| mRenderPassDesc.stencilAttachment = {}; |
| - return updateCachedRenderTarget(context, mState.getStencilAttachment(), &mStencilRenderTarget); |
| + ANGLE_TRY( |
| + updateCachedRenderTarget(context, mState.getStencilAttachment(), &mStencilRenderTarget)); |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + if (mState.getStencilResolveAttachment()) |
| + { |
| + ANGLE_TRY(updateCachedRenderTarget(context, mState.getStencilResolveAttachment(), |
| + &mStencilResolveRenderTarget)); |
| + } |
| +#endif |
| + return angle::Result::Continue; |
| } |
| |
| angle::Result FramebufferMtl::updateCachedRenderTarget(const gl::Context *context, |
| @@ -1090,6 +1143,9 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, |
| |
| mtl::RenderPassColorAttachmentDesc &colorAttachment = desc.colorAttachments[colorIndexGL]; |
| const RenderTargetMtl *colorRenderTarget = mColorRenderTargets[colorIndexGL]; |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + const RenderTargetMtl *colorResolveRenderTarget = mColorResolveRenderTargets[colorIndexGL]; |
| +#endif |
| |
| // GL allows data types of fragment shader color outputs to be incompatible with disabled |
| // color attachments. To prevent various Metal validation issues, assign textures only to |
| @@ -1097,6 +1153,12 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, |
| if (colorRenderTarget && enabledDrawBuffers.test(colorIndexGL)) |
| { |
| colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment); |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + if (colorResolveRenderTarget) |
| + { |
| + colorResolveRenderTarget->toRenderPassResolveAttachmentDesc(&colorAttachment); |
| + } |
| +#endif |
| |
| desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1); |
| desc.rasterSampleCount = |
| @@ -1126,6 +1188,12 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, |
| if (mDepthRenderTarget) |
| { |
| mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment); |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + if (mDepthResolveRenderTarget) |
| + { |
| + mDepthResolveRenderTarget->toRenderPassResolveAttachmentDesc(&desc.depthAttachment); |
| + } |
| +#endif |
| desc.rasterSampleCount = |
| std::max(desc.rasterSampleCount, mDepthRenderTarget->getRenderSamples()); |
| } |
| @@ -1137,6 +1205,12 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, |
| if (mStencilRenderTarget) |
| { |
| mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment); |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + if (mStencilResolveRenderTarget) |
| + { |
| + mStencilResolveRenderTarget->toRenderPassResolveAttachmentDesc(&desc.stencilAttachment); |
| + } |
| +#endif |
| desc.rasterSampleCount = |
| std::max(desc.rasterSampleCount, mStencilRenderTarget->getRenderSamples()); |
| } |
| @@ -1216,7 +1290,7 @@ angle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted( |
| colorAttachment.loadAction = MTLLoadActionLoad; |
| } |
| |
| - if (colorAttachment.hasImplicitMSTexture()) |
| + if (colorAttachment.hasResolveTexture()) |
| { |
| colorAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve; |
| } |
| @@ -1236,7 +1310,7 @@ angle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted( |
| tempDesc.depthAttachment.loadAction = MTLLoadActionLoad; |
| } |
| |
| - if (tempDesc.depthAttachment.hasImplicitMSTexture()) |
| + if (tempDesc.depthAttachment.hasResolveTexture()) |
| { |
| tempDesc.depthAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve; |
| } |
| @@ -1255,7 +1329,7 @@ angle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted( |
| tempDesc.stencilAttachment.loadAction = MTLLoadActionLoad; |
| } |
| |
| - if (tempDesc.stencilAttachment.hasImplicitMSTexture()) |
| + if (tempDesc.stencilAttachment.hasResolveTexture()) |
| { |
| tempDesc.stencilAttachment.storeAction = MTLStoreActionStoreAndMultisampleResolve; |
| } |
| @@ -1423,7 +1497,8 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context, |
| if (clearOpts.clearArea == renderArea && |
| (!clearOpts.clearColor.valid() || allBuffersUnmasked) && |
| (!clearOpts.clearStencil.valid() || |
| - (stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll)) |
| + (stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll) && |
| + !needsRG16UnormMSAAClearWorkaround(contextMtl, clearColorBuffers)) |
| { |
| return clearWithLoadOp(context, clearColorBuffers, clearOpts); |
| } |
| @@ -1431,6 +1506,29 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context, |
| return clearWithDraw(context, clearColorBuffers, clearOpts); |
| } |
| |
| +bool FramebufferMtl::needsRG16UnormMSAAClearWorkaround(const ContextMtl *contextMtl, |
| + gl::DrawBufferMask clearColorBuffers) const |
| +{ |
| + if (!contextMtl->getDisplay()->getFeatures().clearMsaaRg16UnormWithDrawWorkaround.enabled) |
| + { |
| + return false; |
| + } |
| + for (size_t i : clearColorBuffers) |
| + { |
| + if (i >= mColorRenderTargets.size()) |
| + { |
| + break; |
| + } |
| + const RenderTargetMtl *rt = mColorRenderTargets[i]; |
| + if (rt && rt->getRenderSamples() > 1 && |
| + rt->getFormat().metalFormat == MTLPixelFormatRG16Unorm) |
| + { |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| angle::Result FramebufferMtl::invalidateImpl(const gl::Context *context, |
| size_t count, |
| const GLenum *attachments) |
| @@ -1493,31 +1591,54 @@ angle::Result FramebufferMtl::invalidateImpl(const gl::Context *context, |
| } |
| } |
| |
| - mtl::RenderPassColorAttachmentDesc &colorAttachment = |
| - mRenderPassDesc.colorAttachments[i]; |
| + // If the invalidated color buffer has an associated resolve target |
| + // then resolve the MSAA samples, otherwise discard the data. |
| + auto &colorAttachment = mRenderPassDesc.colorAttachments[i]; |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + auto *resolveRenderTarget = mColorResolveRenderTargets[i]; |
| + colorAttachment.storeAction = |
| + resolveRenderTarget ? MTLStoreActionMultisampleResolve : MTLStoreActionDontCare; |
| +#else |
| colorAttachment.storeAction = MTLStoreActionDontCare; |
| +#endif |
| if (renderPassStarted) |
| { |
| - encoder->setColorStoreAction(MTLStoreActionDontCare, i); |
| + encoder->setColorStoreAction(colorAttachment.storeAction, i); |
| } |
| } |
| } |
| |
| if (invalidateDepthBuffer && mDepthRenderTarget) |
| { |
| - mRenderPassDesc.depthAttachment.storeAction = MTLStoreActionDontCare; |
| + // If the invalidated depth buffer has an associated resolve target then |
| + // resolve the MSAA samples, otherwise discard the data. |
| + auto &depthAttachment = mRenderPassDesc.depthAttachment; |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + depthAttachment.storeAction = |
| + mDepthResolveRenderTarget ? MTLStoreActionMultisampleResolve : MTLStoreActionDontCare; |
| +#else |
| + depthAttachment.storeAction = MTLStoreActionDontCare; |
| +#endif |
| if (renderPassStarted) |
| { |
| - encoder->setDepthStoreAction(MTLStoreActionDontCare); |
| + encoder->setDepthStoreAction(depthAttachment.storeAction); |
| } |
| } |
| |
| if (invalidateStencilBuffer && mStencilRenderTarget) |
| { |
| - mRenderPassDesc.stencilAttachment.storeAction = MTLStoreActionDontCare; |
| + // If the invalidated stencil buffer has an associated resolve target |
| + // then resolve the MSAA samples, otherwise discard the data. |
| + auto &stencilAttachment = mRenderPassDesc.stencilAttachment; |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + stencilAttachment.storeAction = |
| + mStencilResolveRenderTarget ? MTLStoreActionMultisampleResolve : MTLStoreActionDontCare; |
| +#else |
| + stencilAttachment.storeAction = MTLStoreActionDontCare; |
| +#endif |
| if (renderPassStarted) |
| { |
| - encoder->setStencilStoreAction(MTLStoreActionDontCare); |
| + encoder->setStencilStoreAction(stencilAttachment.storeAction); |
| } |
| } |
| |
| @@ -1706,7 +1827,8 @@ angle::Result FramebufferMtl::readPixelsToPBO(const gl::Context *context, |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| |
| ANGLE_CHECK_GL_MATH(contextMtl, |
| - packPixelsParams.offset <= std::numeric_limits<uint32_t>::max()); |
| + static_cast<std::make_unsigned_t<decltype(packPixelsParams.offset)>>( |
| + packPixelsParams.offset) <= std::numeric_limits<uint32_t>::max()); |
| uint32_t offset = static_cast<uint32_t>(packPixelsParams.offset); |
| |
| BufferMtl *packBufferMtl = mtl::GetImpl(packPixelsParams.packBuffer); |
| @@ -1854,9 +1976,8 @@ angle::Result FramebufferMtl::unresolveIfNeeded(const gl::Context *context, |
| const mtl::RenderPassColorAttachmentDesc &colorAttachment = |
| renderPassDesc.colorAttachments[colorIndexGL]; |
| |
| - if (colorAttachment.loadAction != MTLLoadActionLoad || |
| - !colorAttachment.hasImplicitMSTexture() || |
| - !colorAttachment.implicitMSTexture->shouldNotLoadStore()) |
| + if (colorAttachment.loadAction != MTLLoadActionLoad || !colorAttachment.texture || |
| + !colorAttachment.texture->shouldNotLoadStore()) |
| { |
| continue; |
| } |
| @@ -1864,9 +1985,9 @@ angle::Result FramebufferMtl::unresolveIfNeeded(const gl::Context *context, |
| const angle::Format &angleFormat = colorRenderTarget->getFormat().actualAngleFormat(); |
| |
| // Blit the resolve texture to the MS texture. |
| - colorBlitParams.src = colorAttachment.texture; |
| - colorBlitParams.srcLevel = colorAttachment.level; |
| - colorBlitParams.srcLayer = colorAttachment.sliceOrDepth; |
| + colorBlitParams.src = colorAttachment.resolveTexture; |
| + colorBlitParams.srcLevel = colorAttachment.resolveLevel; |
| + colorBlitParams.srcLayer = colorAttachment.resolveSliceOrDepth; |
| |
| colorBlitParams.enabledBuffers.reset(); |
| colorBlitParams.enabledBuffers.set(colorIndexGL); |
| @@ -1881,19 +2002,18 @@ angle::Result FramebufferMtl::unresolveIfNeeded(const gl::Context *context, |
| mtl::DepthStencilBlitParams dsBlitParams; |
| dsBlitParams.BlitParams::operator=(baseParams); |
| const mtl::RenderPassDepthAttachmentDesc &depthAttachment = renderPassDesc.depthAttachment; |
| - if (depthAttachment.loadAction == MTLLoadActionLoad && depthAttachment.hasImplicitMSTexture() && |
| - depthAttachment.implicitMSTexture->shouldNotLoadStore()) |
| + if (depthAttachment.loadAction == MTLLoadActionLoad && depthAttachment.texture && |
| + depthAttachment.texture->shouldNotLoadStore()) |
| { |
| - dsBlitParams.src = depthAttachment.texture; |
| - dsBlitParams.srcLevel = depthAttachment.level; |
| - dsBlitParams.srcLayer = depthAttachment.sliceOrDepth; |
| + dsBlitParams.src = depthAttachment.resolveTexture; |
| + dsBlitParams.srcLevel = depthAttachment.resolveLevel; |
| + dsBlitParams.srcLayer = depthAttachment.resolveSliceOrDepth; |
| } |
| |
| const mtl::RenderPassStencilAttachmentDesc &stencilAttachment = |
| renderPassDesc.stencilAttachment; |
| - if (stencilAttachment.loadAction == MTLLoadActionLoad && |
| - stencilAttachment.hasImplicitMSTexture() && |
| - stencilAttachment.implicitMSTexture->shouldNotLoadStore()) |
| + if (stencilAttachment.loadAction == MTLLoadActionLoad && stencilAttachment.texture && |
| + stencilAttachment.texture->shouldNotLoadStore()) |
| { |
| if (mState.hasSeparateDepthAndStencilAttachments()) |
| { |
| @@ -1903,9 +2023,9 @@ angle::Result FramebufferMtl::unresolveIfNeeded(const gl::Context *context, |
| dsBlitParams.src = nullptr; |
| } |
| |
| - dsBlitParams.srcStencil = stencilAttachment.texture->getStencilView(); |
| - dsBlitParams.srcLevel = stencilAttachment.level; |
| - dsBlitParams.srcLayer = stencilAttachment.sliceOrDepth; |
| + dsBlitParams.srcStencil = stencilAttachment.resolveTexture->getStencilView(); |
| + dsBlitParams.srcLevel = stencilAttachment.resolveLevel; |
| + dsBlitParams.srcLayer = stencilAttachment.resolveSliceOrDepth; |
| } |
| |
| if (dsBlitParams.src || dsBlitParams.srcStencil) |
| diff --git a/src/libANGLE/renderer/metal/ImageMtl.mm b/src/libANGLE/renderer/metal/ImageMtl.mm |
| index 71017e47adb8bc8392fb15bbe063430a58d3ca84..a5d041804e92662fccaafe13c535ebc6a0c11a26 100644 |
| --- a/src/libANGLE/renderer/metal/ImageMtl.mm |
| +++ b/src/libANGLE/renderer/metal/ImageMtl.mm |
| @@ -86,7 +86,9 @@ egl::Error TextureImageSiblingMtl::ValidateClientBuffer(const DisplayMtl *displa |
| return egl::Error(EGL_BAD_ATTRIBUTE, "Unrecognized format"); |
| } |
| |
| - if (format.metalFormat != texture.pixelFormat) |
| + angle::FormatID srcAngleFormatId = mtl::Format::MetalToAngleFormatID(texture.pixelFormat); |
| + const mtl::Format &srcFormat = display->getPixelFormat(srcAngleFormatId); |
| + if (!format.isViewCompatible(srcFormat)) |
| { |
| return egl::Error(EGL_BAD_ATTRIBUTE, "Incompatible format"); |
| } |
| @@ -123,18 +125,19 @@ angle::Result TextureImageSiblingMtl::initImpl(DisplayMtl *displayMtl) |
| { |
| mNativeTexture = mtl::Texture::MakeFromMetal((__bridge id<MTLTexture>)(mBuffer)); |
| |
| - if (mNativeTexture->textureType() == MTLTextureType2DArray) |
| + angle::FormatID angleFormatId = intendedFormatForMTLTexture(mNativeTexture->get(), mAttribs); |
| + mFormat = displayMtl->getPixelFormat(angleFormatId); |
| + |
| + if (mNativeTexture->textureType() == MTLTextureType2DArray || |
| + mNativeTexture->pixelFormat() != mFormat.metalFormat) |
| { |
| mtl::TextureRef baseTexture = std::move(mNativeTexture); |
| unsigned textureArraySlice = |
| static_cast<unsigned>(mAttribs.getAsInt(EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 0)); |
| - mNativeTexture = |
| - baseTexture->createSliceMipView(textureArraySlice, mtl::kZeroNativeMipLevel); |
| + mNativeTexture = baseTexture->createSliceMipViewWithCompatibleFormat( |
| + textureArraySlice, mtl::kZeroNativeMipLevel, mFormat.metalFormat); |
| } |
| |
| - angle::FormatID angleFormatId = intendedFormatForMTLTexture(mNativeTexture->get(), mAttribs); |
| - mFormat = displayMtl->getPixelFormat(angleFormatId); |
| - |
| if (mNativeTexture) |
| { |
| size_t resourceSize = EstimateTextureSizeInBytes( |
| diff --git a/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm b/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm |
| index c153696b65bf8e94c4bc912524ab1b42e329e54e..bb6faa0904b2cd3209249460f481f814fb31d4f7 100644 |
| --- a/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm |
| +++ b/src/libANGLE/renderer/metal/ProgramExecutableMtl.mm |
| @@ -894,7 +894,7 @@ angle::Result ProgramExecutableMtl::setupDraw(const gl::Context *glContext, |
| { |
| ContextMtl *context = mtl::GetImpl(glContext); |
| |
| - if (pipelineDescChanged) |
| + if (pipelineDescChanged || !cmdEncoder->hasPipelineState()) |
| { |
| id<MTLFunction> vertexShader = nil; |
| ANGLE_TRY( |
| diff --git a/src/libANGLE/renderer/metal/RenderTargetMtl.h b/src/libANGLE/renderer/metal/RenderTargetMtl.h |
| index 281085bbc46eb7d96dabf73b9c75ee0a61125bab..a07218bc78473252b0b2b9e561ec74799959177e 100644 |
| --- a/src/libANGLE/renderer/metal/RenderTargetMtl.h |
| +++ b/src/libANGLE/renderer/metal/RenderTargetMtl.h |
| @@ -51,6 +51,9 @@ class RenderTargetMtl final : public FramebufferAttachmentRenderTarget |
| const mtl::Format &getFormat() const { return mFormat; } |
| |
| void toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const; |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + void toRenderPassResolveAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const; |
| +#endif |
| |
| private: |
| mtl::TextureWeakRef mTexture; |
| diff --git a/src/libANGLE/renderer/metal/RenderTargetMtl.mm b/src/libANGLE/renderer/metal/RenderTargetMtl.mm |
| index 18e62da867b2916085794ba3b68ee4a3812d3929..6cbf2a58812184edb425d11689bdbce5574917f0 100644 |
| --- a/src/libANGLE/renderer/metal/RenderTargetMtl.mm |
| +++ b/src/libANGLE/renderer/metal/RenderTargetMtl.mm |
| @@ -73,10 +73,33 @@ uint32_t RenderTargetMtl::getRenderSamples() const |
| |
| void RenderTargetMtl::toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *rpaDescOut) const |
| { |
| - rpaDescOut->texture = mTexture.lock(); |
| - rpaDescOut->implicitMSTexture = mImplicitMSTexture.lock(); |
| + mtl::TextureRef implicitMSTex = getImplicitMSTexture(); |
| + mtl::TextureRef tex = getTexture(); |
| + if (implicitMSTex) |
| + { |
| + rpaDescOut->texture = implicitMSTex; |
| + rpaDescOut->resolveTexture = tex; |
| + rpaDescOut->resolveLevel = mLevelIndex; |
| + rpaDescOut->resolveSliceOrDepth = mLayerIndex; |
| + } |
| + else |
| + { |
| + rpaDescOut->texture = tex; |
| rpaDescOut->level = mLevelIndex; |
| rpaDescOut->sliceOrDepth = mLayerIndex; |
| + } |
| rpaDescOut->blendable = mFormat.getCaps().blendable; |
| } |
| + |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| +void RenderTargetMtl::toRenderPassResolveAttachmentDesc( |
| + mtl::RenderPassAttachmentDesc *rpaDescOut) const |
| +{ |
| + ASSERT(!getImplicitMSTexture()); |
| + ASSERT(getRenderSamples() == 1); |
| + rpaDescOut->resolveTexture = getTexture(); |
| + rpaDescOut->resolveLevel = mLevelIndex; |
| + rpaDescOut->resolveSliceOrDepth = mLayerIndex; |
| +} |
| +#endif |
| } // namespace rx |
| diff --git a/src/libANGLE/renderer/metal/SurfaceMtl.mm b/src/libANGLE/renderer/metal/SurfaceMtl.mm |
| index bbe3d9a86e5a4b0f2d6028721a4a2a4e23d3b6b9..c21f5a0454fa503adffac7a199c7e9959972cc0a 100644 |
| --- a/src/libANGLE/renderer/metal/SurfaceMtl.mm |
| +++ b/src/libANGLE/renderer/metal/SurfaceMtl.mm |
| @@ -670,8 +670,9 @@ angle::Result WindowSurfaceMtl::obtainNextDrawable(const gl::Context *context) |
| } |
| mColorTextureInitialized = false; |
| |
| - ANGLE_MTL_LOG("Current metal drawable size=%d,%d", mColorTexture->width(), |
| - mColorTexture->height()); |
| + ANGLE_MTL_LOG("Current metal drawable size=%d,%d", |
| + mColorTexture->width(mtl::MipmapNativeLevel(0)), |
| + mColorTexture->height(mtl::MipmapNativeLevel(0))); |
| |
| // Now we have to resize depth stencil buffers if required. |
| ANGLE_TRY(ensureCompanionTexturesSizeCorrect(context)); |
| diff --git a/src/libANGLE/renderer/metal/TextureMtl.h b/src/libANGLE/renderer/metal/TextureMtl.h |
| index 2c49a4c4b4899d6726c97bbe3049d6a44e575c47..c26b105a375d993114caa4b779e718d91a8934fa 100644 |
| --- a/src/libANGLE/renderer/metal/TextureMtl.h |
| +++ b/src/libANGLE/renderer/metal/TextureMtl.h |
| @@ -190,7 +190,7 @@ class TextureMtl : public TextureImpl |
| GLenum format); |
| |
| private: |
| - void deallocateNativeStorage(bool keepImages, bool keepSamplerStateAndFormat = false); |
| + void deallocateNativeStorage(bool keepImages); |
| angle::Result createNativeStorage(const gl::Context *context, |
| gl::TextureType type, |
| GLuint mips, |
| @@ -205,8 +205,6 @@ class TextureMtl : public TextureImpl |
| // max level is returned (for glGenerateMipmap). |
| GLuint getStorageMipLevelCount(ImageMipLevels mipLevels) const; |
| angle::Result ensureSamplerStateCreated(const gl::Context *context); |
| - // Ensure image at given index is created: |
| - angle::Result ensureImageCreated(const gl::Context *context, const gl::ImageIndex &index); |
| // Ensure all image views at all faces/levels are retained. |
| void retainImageDefinitions(); |
| mtl::TextureRef createImageViewFromTextureStorage(GLuint cubeFaceOrZero, GLuint glLevel); |
| @@ -325,7 +323,7 @@ class TextureMtl : public TextureImpl |
| const uint8_t *pixels, |
| const ImageDefinitionMtl &imageDef); |
| |
| - // Convert pixels to suported format before uploading to texture |
| + // Convert pixels to supported format before uploading to texture. |
| angle::Result convertAndSetPerSliceSubImage(const gl::Context *context, |
| int slice, |
| const MTLRegion &mtlArea, |
| diff --git a/src/libANGLE/renderer/metal/TextureMtl.mm b/src/libANGLE/renderer/metal/TextureMtl.mm |
| index b86f2cd74487f139895d5862e27cccd391e2a40f..50f456c9091474e0ae664b7e872ed4a665c02746 100644 |
| --- a/src/libANGLE/renderer/metal/TextureMtl.mm |
| +++ b/src/libANGLE/renderer/metal/TextureMtl.mm |
| @@ -154,27 +154,6 @@ GLuint GetImageCubeFaceIndexOrZeroFrom(const gl::ImageIndex &index) |
| return 0; |
| } |
| |
| -// Given texture type, get texture type of one image for a glTexImage call. |
| -// For example, for texture 2d, one image is also texture 2d. |
| -// for texture cube, one image is texture 2d. |
| -gl::TextureType GetTextureImageType(gl::TextureType texType) |
| -{ |
| - switch (texType) |
| - { |
| - case gl::TextureType::CubeMap: |
| - return gl::TextureType::_2D; |
| - case gl::TextureType::_2D: |
| - case gl::TextureType::_2DArray: |
| - case gl::TextureType::_2DMultisample: |
| - case gl::TextureType::_3D: |
| - case gl::TextureType::Rectangle: |
| - return texType; |
| - default: |
| - UNREACHABLE(); |
| - return gl::TextureType::InvalidEnum; |
| - } |
| -} |
| - |
| // D24X8 by default writes depth data to high 24 bits of 32 bit integers. However, Metal separate |
| // depth stencil blitting expects depth data to be in low 24 bits of the data. |
| void WriteDepthStencilToDepth24(const uint8_t *srcPtr, uint8_t *dstPtr) |
| @@ -862,7 +841,7 @@ void TextureMtl::onDestroy(const gl::Context *context) |
| mBoundSurface = nullptr; |
| } |
| |
| -void TextureMtl::deallocateNativeStorage(bool keepImages, bool keepSamplerStateAndFormat) |
| +void TextureMtl::deallocateNativeStorage(bool keepImages) |
| { |
| |
| if (!keepImages) |
| @@ -879,6 +858,7 @@ void TextureMtl::deallocateNativeStorage(bool keepImages, bool keepSamplerStateA |
| mNativeTextureStorage = nullptr; |
| mViewFromBaseToMaxLevel = nullptr; |
| mSwizzleStencilSamplingView = nullptr; |
| + mMetalSamplerState = nil; |
| |
| // Clear render target cache for each texture's image. We don't erase them because they |
| // might still be referenced by a framebuffer. |
| @@ -902,11 +882,6 @@ void TextureMtl::deallocateNativeStorage(bool keepImages, bool keepSamplerStateA |
| { |
| view.reset(); |
| } |
| - |
| - if (!keepSamplerStateAndFormat) |
| - { |
| - mMetalSamplerState = nil; |
| - } |
| } |
| |
| GLuint TextureMtl::getStorageMipLevelCount(ImageMipLevels mipLevels) const |
| @@ -960,7 +935,7 @@ angle::Result TextureMtl::ensureNativeStorageCreated(const gl::Context *context, |
| // already-populated image data. |
| if (!isImmutableOrPBuffer() && mNativeTextureStorage->mipmapLevels() < mips) |
| { |
| - deallocateNativeStorage(/*keepImages=*/true, /*keepSamplerStateAndFormat=*/true); |
| + deallocateNativeStorage(/*keepImages=*/true); |
| } |
| else |
| { |
| @@ -985,9 +960,9 @@ angle::Result TextureMtl::ensureNativeStorageCreated(const gl::Context *context, |
| ANGLE_CHECK(contextMtl, desc.format.valid(), gl::err::kInternalError, GL_INVALID_OPERATION); |
| angle::FormatID angleFormatId = |
| angle::Format::InternalFormatToID(desc.format.info->sizedInternalFormat); |
| - mtl::Format format = contextMtl->getPixelFormat(angleFormatId); |
| + const mtl::Format &mtlFormat = contextMtl->getPixelFormat(angleFormatId); |
| |
| - ANGLE_TRY(createNativeStorage(context, mState.getType(), mips, 0, desc.size, format)); |
| + ANGLE_TRY(createNativeStorage(context, mState.getType(), mips, 0, desc.size, mtlFormat)); |
| |
| // Transfer data from defined images to actual texture object |
| int numCubeFaces = static_cast<int>(mNativeTextureStorage->cubeFaces()); |
| @@ -1016,7 +991,7 @@ angle::Result TextureMtl::ensureNativeStorageCreated(const gl::Context *context, |
| |
| // Invalidate texture image definition at this index so that we can make it a |
| // view of the native texture at this index later. |
| - imageToTransfer = nullptr; |
| + mTexImageDefs[face][imageMipLevel] = {}; |
| } |
| } |
| } |
| @@ -1250,7 +1225,7 @@ angle::Result TextureMtl::onBaseMaxLevelsChanged(const gl::Context *context) |
| // Note: We release the native texture storage but keep old image definitions. So that when the |
| // storage is recreated, its levels can be recreated with data from the old image definitions |
| // respectively. |
| - deallocateNativeStorage(/*keepImages=*/true, /*keepSamplerStateAndFormat=*/true); |
| + deallocateNativeStorage(/*keepImages=*/true); |
| |
| // Tell context to rebind textures |
| contextMtl->invalidateCurrentTextures(); |
| @@ -1258,25 +1233,6 @@ angle::Result TextureMtl::onBaseMaxLevelsChanged(const gl::Context *context) |
| return angle::Result::Continue; |
| } |
| |
| -angle::Result TextureMtl::ensureImageCreated(const gl::Context *context, |
| - const gl::ImageIndex &index) |
| -{ |
| - mtl::TextureRef &image = getImage(index); |
| - if (!image) |
| - { |
| - ContextMtl *contextMtl = mtl::GetImpl(context); |
| - |
| - // Image at this level hasn't been defined yet. We need to define it: |
| - const gl::ImageDesc &desc = mState.getImageDesc(index); |
| - angle::FormatID angleFormatId = |
| - angle::Format::InternalFormatToID(desc.format.info->sizedInternalFormat); |
| - mtl::Format format = contextMtl->getPixelFormat(angleFormatId); |
| - |
| - ANGLE_TRY(redefineImage(context, index, format, desc.size)); |
| - } |
| - return angle::Result::Continue; |
| -} |
| - |
| angle::Result TextureMtl::ensureLevelViewsWithinBaseMaxCreated() |
| { |
| ASSERT(mViewFromBaseToMaxLevel); |
| @@ -1411,38 +1367,27 @@ angle::Result TextureMtl::getRenderTarget(ContextMtl *context, |
| ? gl::RenderToTextureImageIndex::Default |
| : static_cast<gl::RenderToTextureImageIndex>(PackSampleCount(implicitSamples)); |
| |
| - ImageDefinitionMtl &imageDef = getImageDefinition(imageIndex); |
| - mtl::Format format = context->getPixelFormat(imageDef.formatID); |
| - |
| - GLuint layer = GetImageLayerIndexFrom(imageIndex); |
| RenderTargetMtl &rtt = mRenderTargets[imageIndex][renderToTextureIndex]; |
| if (!rtt.getTexture()) |
| { |
| - // Lazy initialization of render target: |
| - if (imageDef.image) |
| - { |
| - if (imageIndex.getType() == gl::TextureType::CubeMap) |
| - { |
| - // Cube map is special, the image is already the view of its layer |
| - rtt.set(imageDef.image, mtl::kZeroNativeMipLevel, 0, format); |
| - } |
| - else |
| - { |
| - rtt.set(imageDef.image, mtl::kZeroNativeMipLevel, layer, format); |
| - } |
| - } |
| + auto &imageDef = getImageDefinition(imageIndex); |
| + ANGLE_CHECK_ASSERT(context, imageDef.image && imageDef.image->valid()); |
| + // Cube map is special, the image is already the view of its layer. |
| + GLuint layer = imageIndex.getType() == gl::TextureType::CubeMap ? 0 : GetImageLayerIndexFrom(imageIndex); |
| + const mtl::Format &mtlFormat = context->getPixelFormat(imageDef.formatID); |
| + rtt.set(imageDef.image, mtl::kZeroNativeMipLevel, layer, mtlFormat); |
| } |
| |
| if (implicitSamples > 1 && !rtt.getImplicitMSTexture()) |
| { |
| // This format must supports implicit resolve |
| - ANGLE_CHECK(context, format.getCaps().resolve, gl::err::kInternalError, GL_INVALID_VALUE); |
| + ANGLE_CHECK_ASSERT(context, rtt.getFormat().getCaps().resolve); |
| mtl::TextureRef &msTexture = mImplicitMSTextures[imageIndex][renderToTextureIndex]; |
| if (!msTexture) |
| { |
| const gl::ImageDesc &desc = mState.getImageDesc(imageIndex); |
| ANGLE_TRY(mtl::Texture::MakeMemoryLess2DMSTexture( |
| - context, format, desc.size.width, desc.size.height, implicitSamples, &msTexture)); |
| + context, rtt.getFormat(), desc.size.width, desc.size.height, implicitSamples, &msTexture)); |
| } |
| rtt.setImplicitMSTexture(msTexture); |
| } |
| @@ -1736,7 +1681,20 @@ angle::Result TextureMtl::generateMipmap(const gl::Context *context) |
| ANGLE_TRY(ensureNativeStorageCreated(context, /*keepImages=*/false, |
| ImageMipLevels::FullMipChainForGenerateMipmap)); |
| |
| + int numCubeFaces = static_cast<int>(mNativeTextureStorage->cubeFaces()); |
| + for (int face = 0; face < numCubeFaces; ++face) |
| + { |
| + const GLuint mips = mNativeTextureStorage->mipmapLevels(); |
| + for (mtl::MipmapNativeLevel mip = mtl::kZeroNativeMipLevel; mip.get() < mips; ++mip) |
| + { |
| + GLuint level = mNativeTextureStorage->getGLLevel(mip); |
| + // Recreate views conservatively. All views should point to mNativeTextureStorage. |
| + mTexImageDefs[face][level] = {}; |
| + } |
| + } |
| + |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| + contextMtl->invalidateCurrentTextures(); |
| if (!mViewFromBaseToMaxLevel) |
| { |
| return angle::Result::Continue; |
| @@ -1779,8 +1737,7 @@ angle::Result TextureMtl::generateMipmapCPU(const gl::Context *context) |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| const angle::Format &angleFormat = mViewFromBaseToMaxLevel->getFormat().actualAngleFormat(); |
| // This format must have mip generation function. |
| - ANGLE_CHECK(contextMtl, angleFormat.mipGenerationFunction, gl::err::kInternalError, |
| - GL_INVALID_OPERATION); |
| + ANGLE_CHECK_ASSERT(contextMtl, angleFormat.mipGenerationFunction); |
| |
| for (uint32_t slice = 0; slice < mSlices; ++slice) |
| { |
| @@ -2106,54 +2063,40 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context, |
| const mtl::Format &mtlFormat, |
| const gl::Extents &size) |
| { |
| - bool imageWithinNativeStorageLevels = false; |
| - if (mNativeTextureStorage && mNativeTextureStorage->isGLLevelSupported(index.getLevelIndex())) |
| - { |
| - imageWithinNativeStorageLevels = true; |
| + GLuint cubeFaceOrZero = GetImageCubeFaceIndexOrZeroFrom(index); |
| GLuint glLevel = index.getLevelIndex(); |
| - // Calculate the expected size for the index we are defining. If the size is different |
| - // from the given size, or the format is different, we are redefining the image so we |
| - // must release it. |
| + ImageDefinitionMtl &imageDef = mTexImageDefs[cubeFaceOrZero][glLevel]; |
| + |
| + if (mNativeTextureStorage && mNativeTextureStorage->isGLLevelSupported(glLevel)) |
| + { |
| + // mNativeTextureStorage stores the complete mipmap chain when present. |
| ASSERT(mNativeTextureStorage->textureType() == mtl::GetTextureType(index.getType())); |
| - if (mNativeTextureStorage->getFormat() != mtlFormat || |
| - size != mNativeTextureStorage->size(glLevel)) |
| + if (mNativeTextureStorage->getFormat() == mtlFormat && size == mNativeTextureStorage->size(glLevel)) |
| { |
| - // Keep other images |
| - deallocateNativeStorage(/*keepImages=*/true); |
| + // The view might be from mNativeTextureStorage, but it might also be from previous |
| + // storages. Always discard. |
| + imageDef = {}; |
| + return angle::Result::Continue; |
| } |
| + // The redefinition makes the mipmap chain incomplete. Move the mipmaps to |
| + // detached views. |
| + deallocateNativeStorage(/*keepImages=*/true); |
| } |
| |
| + // The detached view might be not match format or size, currently we do not reuse these. |
| + imageDef = {}; |
| + |
| + ContextMtl *contextMtl = mtl::GetImpl(context); |
| + // Tell context to rebind textures |
| + contextMtl->invalidateCurrentTextures(); |
| + |
| // Early-out on empty textures, don't create a zero-sized storage. |
| if (size.empty()) |
| { |
| return angle::Result::Continue; |
| } |
| |
| - ContextMtl *contextMtl = mtl::GetImpl(context); |
| - ImageDefinitionMtl &imageDef = getImageDefinition(index); |
| - |
| - // If native texture still exists, it means the size hasn't been changed, no need to create new |
| - // image |
| - if (mNativeTextureStorage && imageWithinNativeStorageLevels) |
| - { |
| - if (imageDef.image && |
| - imageDef.image->textureType() == |
| - mtl::GetTextureType(GetTextureImageType(index.getType())) && |
| - imageDef.formatID == mNativeTextureStorage->getFormat().intendedFormatId && |
| - imageDef.image->sizeAt0() == size) |
| - { |
| - // Keep it! (No-op) |
| - } |
| - else |
| - { |
| - // Recreate the view at this index. |
| - imageDef.image = nullptr; |
| - imageDef = getImageDefinition(index); |
| - } |
| - } |
| - else |
| - { |
| - imageDef.formatID = mtlFormat.intendedFormatId; |
| + mtl::TextureRef image; |
| bool allowFormatView = |
| mtlFormat.hasDepthAndStencilBits() || |
| needsFormatViewForPixelLocalStorage( |
| @@ -2165,29 +2108,26 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context, |
| case gl::TextureType::CubeMap: |
| ANGLE_TRY(mtl::Texture::Make2DTexture( |
| contextMtl, mtlFormat, size.width, size.height, 1, |
| - /** renderTargetOnly */ false, allowFormatView, &imageDef.image)); |
| + /** renderTargetOnly */ false, allowFormatView, &image)); |
| break; |
| case gl::TextureType::_3D: |
| ANGLE_TRY(mtl::Texture::Make3DTexture( |
| contextMtl, mtlFormat, size.width, size.height, size.depth, 1, |
| - /** renderTargetOnly */ false, allowFormatView, &imageDef.image)); |
| + /** renderTargetOnly */ false, allowFormatView, &image)); |
| break; |
| case gl::TextureType::_2DArray: |
| ANGLE_TRY(mtl::Texture::Make2DArrayTexture( |
| contextMtl, mtlFormat, size.width, size.height, 1, size.depth, |
| - /** renderTargetOnly */ false, allowFormatView, &imageDef.image)); |
| + /** renderTargetOnly */ false, allowFormatView, &image)); |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| |
| // Make sure emulated channels are properly initialized in this newly allocated texture. |
| - ANGLE_TRY(initializeNowIfNeeded(context, mtlFormat, imageDef.image)); |
| - } |
| - |
| - // Tell context to rebind textures |
| - contextMtl->invalidateCurrentTextures(); |
| + ANGLE_TRY(initializeNowIfNeeded(context, mtlFormat, image)); |
| |
| + imageDef = {image, mtlFormat.intendedFormatId}; |
| return angle::Result::Continue; |
| } |
| |
| @@ -2205,7 +2145,6 @@ angle::Result TextureMtl::setStorageImpl(const gl::Context *context, |
| |
| // Tell context to rebind textures |
| contextMtl->invalidateCurrentTextures(); |
| - |
| ANGLE_TRY(createNativeStorage(context, type, mips, samples, size, mtlFormat)); |
| ANGLE_TRY(createViewFromBaseToMaxLevel()); |
| |
| @@ -2265,15 +2204,15 @@ angle::Result TextureMtl::setSubImageImpl(const gl::Context *context, |
| |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| |
| - ANGLE_TRY(ensureImageCreated(context, index)); |
| ImageDefinitionMtl &imageDef = getImageDefinition(index); |
| - |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| GLuint sourceRowPitch = 0; |
| GLuint sourceDepthPitch = 0; |
| GLuint sourceSkipBytes = 0; |
| - ANGLE_CHECK_GL_MATH(contextMtl, formatInfo.computeRowDepthSkipBytes( |
| - type, area.width, area.height, unpack, index.usesTex3D(), |
| - &sourceRowPitch, &sourceDepthPitch, &sourceSkipBytes)); |
| + ANGLE_CHECK_GL_MATH( |
| + contextMtl, formatInfo.computeRowDepthSkipBytes( |
| + type, area.width, area.height, unpack, |
| + index.usesTex3D(), &sourceRowPitch, &sourceDepthPitch, &sourceSkipBytes)); |
| |
| // Get corresponding source data's ANGLE format |
| angle::FormatID srcAngleFormatId; |
| @@ -2461,9 +2400,8 @@ angle::Result TextureMtl::convertAndSetPerSliceSubImage(const gl::Context *conte |
| const uint8_t *pixels, |
| const ImageDefinitionMtl &imageDef) |
| { |
| - ASSERT(imageDef.image && imageDef.image->valid()); |
| - |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| mtl::Format imageFormat = contextMtl->getPixelFormat(imageDef.formatID); |
| |
| if (unpackBuffer) |
| @@ -2710,9 +2648,9 @@ angle::Result TextureMtl::initializeContents(const gl::Context *context, |
| } |
| |
| ASSERT(index.getLayerCount() == 1 && !index.isLayered()); |
| - ANGLE_TRY(ensureImageCreated(context, index)); |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| ImageDefinitionMtl &imageDef = getImageDefinition(index); |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| const mtl::TextureRef &image = imageDef.image; |
| const mtl::Format &format = contextMtl->getPixelFormat(imageDef.formatID); |
| // For Texture's image definition, we always use zero mip level. |
| @@ -2754,13 +2692,11 @@ angle::Result TextureMtl::copySubImageImpl(const gl::Context *context, |
| const gl::Offset modifiedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x, |
| destOffset.y + clippedSourceArea.y - sourceArea.y, 0); |
| |
| - ANGLE_TRY(ensureImageCreated(context, index)); |
| - |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| - mtl::Format format = contextMtl->getPixelFormat( |
| - angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat)); |
| - |
| - if (!format.getCaps().isRenderable()) |
| + auto &imageDef = getImageDefinition(index); |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| + mtl::Format mtlFormat = contextMtl->getPixelFormat(imageDef.formatID); |
| + if (!mtlFormat.getCaps().isRenderable()) |
| { |
| return copySubImageCPU(context, index, modifiedDestOffset, clippedSourceArea, |
| internalFormat, source, colorReadRT); |
| @@ -2816,14 +2752,11 @@ angle::Result TextureMtl::copySubImageCPU(const gl::Context *context, |
| const FramebufferMtl *source, |
| const RenderTargetMtl *colorReadRT) |
| { |
| - mtl::TextureRef &image = getImage(index); |
| - ASSERT(image && image->valid()); |
| - |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| + auto &imageDef = getImageDefinition(index); |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| |
| - mtl::Format format = contextMtl->getPixelFormat( |
| - angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat)); |
| - const angle::Format &dstFormat = angle::Format::Get(format.actualFormatId); |
| + const angle::Format &dstFormat = angle::Format::Get(imageDef.formatID); |
| const int dstRowPitch = dstFormat.pixelBytes * clippedSourceArea.width; |
| angle::MemoryBuffer conversionRow; |
| ANGLE_CHECK_GL_ALLOC(contextMtl, conversionRow.resize(dstRowPitch)); |
| @@ -2870,7 +2803,7 @@ angle::Result TextureMtl::copySubImageCPU(const gl::Context *context, |
| // Upload to texture |
| ANGLE_TRY(UploadTextureContents(context, dstFormat, mtlDstRowArea, mtl::kZeroNativeMipLevel, |
| dstSlice, conversionRow.data(), dstRowPitch, 0, |
| - kAvoidStagingBuffers, image)); |
| + kAvoidStagingBuffers, imageDef.image)); |
| } |
| |
| return angle::Result::Continue; |
| @@ -2895,18 +2828,15 @@ angle::Result TextureMtl::copySubTextureImpl(const gl::Context *context, |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| TextureMtl *sourceMtl = mtl::GetImpl(source); |
| |
| - ANGLE_TRY(ensureImageCreated(context, index)); |
| - |
| - ANGLE_TRY(sourceMtl->ensureImageCreated(context, sourceIndex)); |
| - |
| - const ImageDefinitionMtl &srcImageDef = sourceMtl->getImageDefinition(sourceIndex); |
| - const mtl::TextureRef &sourceImage = srcImageDef.image; |
| - const mtl::Format &sourceFormat = contextMtl->getPixelFormat(srcImageDef.formatID); |
| + const ImageDefinitionMtl &imageDef = getImageDefinition(index); |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| + const ImageDefinitionMtl &sourceImageDef = sourceMtl->getImageDefinition(sourceIndex); |
| + ANGLE_CHECK_ASSERT(contextMtl, sourceImageDef.image && sourceImageDef.image->valid()); |
| + const mtl::Format &mtlFormat = contextMtl->getPixelFormat(imageDef.formatID); |
| + const mtl::TextureRef &sourceImage = sourceImageDef.image; |
| + const mtl::Format &sourceFormat = contextMtl->getPixelFormat(sourceImageDef.formatID); |
| const angle::Format &sourceAngleFormat = sourceFormat.actualAngleFormat(); |
| - |
| - mtl::Format format = contextMtl->getPixelFormat( |
| - angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat)); |
| - if (!format.getCaps().isRenderable()) |
| + if (!mtlFormat.getCaps().isRenderable()) |
| { |
| return copySubTextureCPU(context, index, destOffset, internalFormat, |
| mtl::kZeroNativeMipLevel, sourceBox, sourceAngleFormat, |
| @@ -2931,10 +2861,9 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context, |
| const mtl::TextureRef &sourceTexture) |
| { |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| - DisplayMtl *displayMtl = contextMtl->getDisplay(); |
| - |
| - mtl::TextureRef image = getImage(index); |
| - ASSERT(image && image->valid()); |
| + auto &imageDef = getImageDefinition(index); |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| + mtl::TextureRef image = imageDef.image; |
| |
| if (internalFormat.colorEncoding == GL_SRGB) |
| { |
| @@ -2949,7 +2878,7 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context, |
| blitParams.dstRect = |
| gl::Rectangle(destOffset.x, destOffset.y, sourceBox.width, sourceBox.height); |
| blitParams.dstScissorRect = blitParams.dstRect; |
| - |
| + const angle::Format &dstAngleFormat = angle::Format::Get(imageDef.formatID); |
| blitParams.enabledBuffers.set(0); |
| |
| blitParams.src = sourceTexture; |
| @@ -2964,10 +2893,9 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context, |
| blitParams.unpackUnmultiplyAlpha = unpackUnmultiplyAlpha; |
| blitParams.transformLinearToSrgb = sourceAngleFormat.isSRGB; |
| |
| - mtl::Format format = contextMtl->getPixelFormat( |
| - angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat)); |
| + DisplayMtl *displayMtl = contextMtl->getDisplay(); |
| return displayMtl->getUtils().copyTextureWithDraw(context, cmdEncoder, sourceAngleFormat, |
| - format.actualAngleFormat(), blitParams); |
| + dstAngleFormat, blitParams); |
| } |
| |
| angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context, |
| @@ -2982,14 +2910,11 @@ angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context, |
| bool unpackUnmultiplyAlpha, |
| const mtl::TextureRef &sourceTexture) |
| { |
| - mtl::TextureRef &image = getImage(index); |
| - ASSERT(image && image->valid()); |
| - |
| ContextMtl *contextMtl = mtl::GetImpl(context); |
| + auto &imageDef = getImageDefinition(index); |
| + ANGLE_CHECK_ASSERT(contextMtl, imageDef.image && imageDef.image->valid()); |
| |
| - mtl::Format format = contextMtl->getPixelFormat( |
| - angle::Format::InternalFormatToID(internalFormat.sizedInternalFormat)); |
| - const angle::Format &dstAngleFormat = format.actualAngleFormat(); |
| + const angle::Format &dstAngleFormat = angle::Format::Get(imageDef.formatID); |
| const int srcRowPitch = sourceAngleFormat.pixelBytes * sourceBox.width; |
| const int srcImageSize = srcRowPitch * sourceBox.height; |
| const int convRowPitch = dstAngleFormat.pixelBytes * sourceBox.width; |
| @@ -3017,7 +2942,7 @@ angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context, |
| |
| // Upload to texture |
| ANGLE_TRY(UploadTextureContents(context, dstAngleFormat, mtlDstArea, mtl::kZeroNativeMipLevel, |
| - 0, conversionDst.data(), convRowPitch, 0, false, image)); |
| + 0, conversionDst.data(), convRowPitch, 0, false, imageDef.image)); |
| |
| return angle::Result::Continue; |
| } |
| diff --git a/src/libANGLE/renderer/metal/VertexArrayMtl.h b/src/libANGLE/renderer/metal/VertexArrayMtl.h |
| index 6115160fee12ba87e55e99644c5a441d45e0dc36..ee8666b1e0b74dc888125a816a04e56f69df92bd 100644 |
| --- a/src/libANGLE/renderer/metal/VertexArrayMtl.h |
| +++ b/src/libANGLE/renderer/metal/VertexArrayMtl.h |
| @@ -42,6 +42,7 @@ class VertexArrayMtl : public VertexArrayImpl |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| GLsizei instanceCount, |
| + GLuint baseInstance, |
| gl::DrawElementsType indexTypeOrInvalid, |
| const void *indices); |
| |
| diff --git a/src/libANGLE/renderer/metal/VertexArrayMtl.mm b/src/libANGLE/renderer/metal/VertexArrayMtl.mm |
| index bafb21532d88109cb5a374a921b4eff920306ca8..e29cef56ea1126b0f93606f9aed748c859ffa8f1 100644 |
| --- a/src/libANGLE/renderer/metal/VertexArrayMtl.mm |
| +++ b/src/libANGLE/renderer/metal/VertexArrayMtl.mm |
| @@ -15,6 +15,7 @@ |
| |
| #include <TargetConditionals.h> |
| |
| +#include "common/mathutil.h" |
| #include "libANGLE/ErrorStrings.h" |
| #include "libANGLE/renderer/metal/BufferMtl.h" |
| #include "libANGLE/renderer/metal/ContextMtl.h" |
| @@ -106,20 +107,21 @@ size_t GetVertexCount(BufferMtl *srcBuffer, |
| const gl::VertexBinding &binding, |
| uint32_t srcFormatSize) |
| { |
| - // Bytes usable for vertex data. |
| - GLint64 bytes = srcBuffer->size() - binding.getOffset(); |
| - if (bytes < srcFormatSize) |
| + GLintptr bindingOffset = binding.getOffset(); |
| + if (bindingOffset < 0) |
| return 0; |
| |
| + // Bytes usable for vertex data. |
| + angle::CheckedNumeric<size_t> bytes = srcBuffer->size(); |
| + bytes -= static_cast<size_t>(bindingOffset); |
| // Count the last vertex. It may occupy less than a full stride. |
| - size_t numVertices = 1; |
| bytes -= srcFormatSize; |
| + if (!bytes.IsValid()) |
| + return 0; |
| |
| // Count how many strides fit remaining space. |
| - if (bytes > 0) |
| - numVertices += static_cast<size_t>(bytes) / binding.getStride(); |
| - |
| - return numVertices; |
| + size_t effectiveStride = binding.getStride() > 0 ? binding.getStride() : srcFormatSize; |
| + return 1 + static_cast<size_t>(bytes.ValueOrDie()) / effectiveStride; |
| } |
| |
| size_t GetVertexCountWithConversion(BufferMtl *srcBuffer, |
| @@ -127,21 +129,24 @@ size_t GetVertexCountWithConversion(BufferMtl *srcBuffer, |
| const gl::VertexBinding &binding, |
| uint32_t srcFormatSize) |
| { |
| - // Bytes usable for vertex data. |
| - GLint64 bytes = srcBuffer->size() - |
| - MIN(static_cast<uintptr_t>(conversionBuffer->offset), binding.getOffset()); |
| - if (bytes < srcFormatSize) |
| + // Use the smaller of the conversion buffer offset and the binding offset. |
| + GLintptr bindingOffset = binding.getOffset(); |
| + if (bindingOffset < 0) |
| return 0; |
| + size_t effectiveOffset = |
| + std::min(conversionBuffer->offset, static_cast<size_t>(bindingOffset)); |
| |
| + // Bytes usable for vertex data. |
| + angle::CheckedNumeric<size_t> bytes = srcBuffer->size(); |
| + bytes -= effectiveOffset; |
| // Count the last vertex. It may occupy less than a full stride. |
| - size_t numVertices = 1; |
| bytes -= srcFormatSize; |
| + if (!bytes.IsValid()) |
| + return 0; |
| |
| // Count how many strides fit remaining space. |
| - if (bytes > 0) |
| - numVertices += static_cast<size_t>(bytes) / binding.getStride(); |
| - |
| - return numVertices; |
| + size_t effectiveStride = binding.getStride() > 0 ? binding.getStride() : srcFormatSize; |
| + return 1 + static_cast<size_t>(bytes.ValueOrDie()) / effectiveStride; |
| } |
| |
| inline MTLVertexFormat GetCurrentAttribFormat(GLenum type) |
| @@ -462,6 +467,7 @@ angle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context, |
| GLint firstVertex, |
| GLsizei vertexOrIndexCount, |
| GLsizei instanceCount, |
| + GLuint baseInstance, |
| gl::DrawElementsType indexTypeOrInvalid, |
| const void *indices) |
| { |
| @@ -500,8 +506,10 @@ angle::Result VertexArrayMtl::updateClientAttribs(const gl::Context *context, |
| } |
| else |
| { |
| - // Per instance attribute |
| - startElement = 0; |
| + // Per instance attribute. The GPU vertex fetcher reads element index |
| + // baseInstance + floor(instance / divisor), so the buffer/inline-data range |
| + // must extend through the highest such index. |
| + startElement = baseInstance; |
| elementCount = UnsignedCeilDivide(instanceCount, binding.getDivisor()); |
| } |
| size_t bytesIntendedToUse = (startElement + elementCount) * binding.getStride(); |
| @@ -615,17 +623,27 @@ angle::Result VertexArrayMtl::syncDirtyAttrib(const gl::Context *glContext, |
| (binding.getStride() < format.actualAngleFormat().pixelBytes) || |
| (binding.getStride() % mtl::kVertexAttribBufferStrideAlignment) != 0; |
| |
| - if (needConversion) |
| + unsigned srcFormatSize = format.actualAngleFormat().pixelBytes; |
| + size_t numVertices = GetVertexCount(bufferMtl, binding, srcFormatSize); |
| + if (numVertices == 0) |
| + { |
| + // Out of bound buffer access, can return any values. |
| + // See KHR_robust_buffer_access_behavior. |
| + mCurrentArrayBuffers[attribIndex] = bufferMtl; |
| + mCurrentArrayBufferFormats[attribIndex] = &format; |
| + mCurrentArrayBufferOffsets[attribIndex] = 0; |
| + mCurrentArrayBufferStrides[attribIndex] = 16; |
| + } |
| + else if (needConversion) |
| { |
| ANGLE_TRY(convertVertexBuffer(glContext, bufferMtl, binding, attribIndex, format)); |
| } |
| else |
| { |
| mCurrentArrayBuffers[attribIndex] = bufferMtl; |
| + mCurrentArrayBufferFormats[attribIndex] = &format; |
| mCurrentArrayBufferOffsets[attribIndex] = binding.getOffset(); |
| mCurrentArrayBufferStrides[attribIndex] = binding.getStride(); |
| - |
| - mCurrentArrayBufferFormats[attribIndex] = &format; |
| } |
| } |
| else |
| @@ -1037,18 +1055,6 @@ angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext, |
| { |
| unsigned srcFormatSize = srcVertexFormat.intendedAngleFormat().pixelBytes; |
| |
| - size_t numVertices = GetVertexCount(srcBuffer, binding, srcFormatSize); |
| - if (numVertices == 0) |
| - { |
| - // Out of bound buffer access, can return any values. |
| - // See KHR_robust_buffer_access_behavior |
| - mCurrentArrayBuffers[attribIndex] = srcBuffer; |
| - mCurrentArrayBufferFormats[attribIndex] = &srcVertexFormat; |
| - mCurrentArrayBufferOffsets[attribIndex] = 0; |
| - mCurrentArrayBufferStrides[attribIndex] = 16; |
| - return angle::Result::Continue; |
| - } |
| - |
| ContextMtl *contextMtl = mtl::GetImpl(glContext); |
| |
| // Convert to tightly packed format |
| @@ -1075,7 +1081,7 @@ angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext, |
| mCurrentArrayBufferStrides[attribIndex] = stride; |
| return angle::Result::Continue; |
| } |
| - numVertices = GetVertexCountWithConversion( |
| + size_t numVertices = GetVertexCountWithConversion( |
| srcBuffer, static_cast<VertexConversionBufferMtl *>(conversion), binding, srcFormatSize); |
| |
| const angle::Format &convertedAngleFormat = convertedFormat.actualAngleFormat(); |
| @@ -1161,16 +1167,27 @@ angle::Result VertexArrayMtl::convertVertexBufferGPU(const gl::Context *glContex |
| mtl::BufferSlice newBuffer; |
| ANGLE_TRY(conversion->bufferPool.allocate(contextMtl, numVertices * targetStride, &newBuffer)); |
| |
| - ANGLE_CHECK_GL_MATH(contextMtl, binding.getOffset() <= std::numeric_limits<uint32_t>::max()); |
| + GLintptr bindingOffset = binding.getOffset(); |
| + |
| + if constexpr (sizeof(bindingOffset) > sizeof(uint32_t)) |
| + { |
| + ANGLE_CHECK_GL_MATH(contextMtl, static_cast<std::make_unsigned_t<decltype(bindingOffset)>>( |
| + bindingOffset) <= std::numeric_limits<uint32_t>::max()); |
| + } |
| ANGLE_CHECK_GL_MATH(contextMtl, newBuffer.offset() <= std::numeric_limits<uint32_t>::max()); |
| ANGLE_CHECK_GL_MATH(contextMtl, numVertices <= std::numeric_limits<uint32_t>::max()); |
| |
| mtl::VertexFormatConvertParams params; |
| VertexConversionBufferMtl *vertexConversion = |
| static_cast<VertexConversionBufferMtl *>(conversion); |
| + if constexpr (sizeof(vertexConversion->offset) > sizeof(uint32_t)) |
| + { |
| + ANGLE_CHECK_GL_MATH(contextMtl, |
| + vertexConversion->offset <= std::numeric_limits<uint32_t>::max()); |
| + } |
| params.srcBuffer = srcBuffer->getCurrentBuffer(); |
| - params.srcBufferStartOffset = static_cast<uint32_t>( |
| - MIN(static_cast<uintptr_t>(vertexConversion->offset), binding.getOffset())); |
| + params.srcBufferStartOffset = std::min(static_cast<uint32_t>(vertexConversion->offset), |
| + static_cast<uint32_t>(bindingOffset)); |
| params.srcStride = binding.getStride(); |
| params.srcDefaultAlphaData = convertedFormat.defaultAlpha; |
| |
| diff --git a/src/libANGLE/renderer/metal/gen_mtl_format_table.py b/src/libANGLE/renderer/metal/gen_mtl_format_table.py |
| index 46c1605f23684116449773bcf062c97a440ab8f9..6918271fd0c3dd2b1b2a130c7ceb3401a82392fc 100644 |
| --- a/src/libANGLE/renderer/metal/gen_mtl_format_table.py |
| +++ b/src/libANGLE/renderer/metal/gen_mtl_format_table.py |
| @@ -98,7 +98,18 @@ void FormatTable::initNativeFormatCapsAutogen(const DisplayMtl *display) |
| bool supportDepthStencilAutoResolve = supportDepthAutoResolve && supportStencilAutoResolve; |
| |
| // Source: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf |
| - {metal_format_caps} |
| + // clang-format off |
| +{metal_format_caps} |
| + // clang-format on |
| + |
| +#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) |
| + const bool supportsiOS2 = SupportsAppleGPUFamily(display->getMetalDevice(), 2); |
| + const bool supportsiOS4 = SupportsAppleGPUFamily(display->getMetalDevice(), 4); |
| + for (auto &entry : mNativePixelFormatCapsTable) |
| + {{ |
| + adjustFormatCapsForDevice(entry.first, supportsiOS2, supportsiOS4); |
| + }} |
| +#endif |
| }} |
| |
| }} // namespace mtl |
| @@ -220,6 +231,66 @@ def maybe_add_deprecation_warning_supression(is_deprecated_pixel_format, |
| def is_format_deprecated(pixel_format): |
| return 'MTLPixelFormatPVRTC_RGB' in pixel_format |
| |
| + |
| +def is_format_compressed(mtl_format): |
| + name = mtl_format.replace('MTLPixelFormat', '') |
| + return any(name.startswith(prefix) for prefix in ['BC', 'ETC', 'EAC', 'PVRTC', 'ASTC']) |
| + |
| + |
| +def get_mtl_format_info(mtl_format): |
| + """Extract channel count and pixel byte size from an MTLPixelFormat name. |
| + |
| + For depth/stencil formats, returns channels=0 with the correct pixel byte size. |
| + Examples: |
| + MTLPixelFormatRGBA32Float -> (4, 16, 4) # 4 channels, 4 bytes each, alignment 4 |
| + MTLPixelFormatRG16Float -> (2, 4, 2) # 2 channels, 2 bytes each, alignment 2 |
| + MTLPixelFormatR8Unorm -> (1, 1, 1) # 1 channel, 1 byte, alignment 1 |
| + MTLPixelFormatDepth32Float -> (0, 4, 4) # depth, 4 bytes, alignment 4 |
| + MTLPixelFormatDepth16Unorm -> (0, 2, 2) # depth, 2 bytes, alignment 2 |
| + MTLPixelFormatStencil8 -> (0, 1, 1) # stencil, 1 byte, alignment 1 |
| + MTLPixelFormatDepth32Float_Stencil8 -> (0, 5, 4) # depth+stencil, 5 bytes, alignment 4 |
| + """ |
| + name = mtl_format.replace('MTLPixelFormat', '') |
| + |
| + if name == 'Invalid': |
| + return 0, 0, 0 |
| + |
| + base_name = name.replace('_sRGB', '') |
| + |
| + predefined_formats = { |
| + 'Depth32Float': (0, 4, 4), |
| + 'Depth16Unorm': (0, 2, 2), |
| + 'Stencil8': (0, 1, 1), |
| + 'Depth32Float_Stencil8': |
| + (0, 5, 4 |
| + ), # "When using this format, some Metal device objects allocate 64-bits per pixel." |
| + 'Depth24Unorm_Stencil8': (0, 4, 4), |
| + 'BGR10A2Unorm': (4, 4, 4), |
| + 'RGB10A2Unorm': (4, 4, 4), |
| + 'RGB10A2Uint': (4, 4, 4), |
| + 'RG11B10Float': (3, 4, 4), |
| + 'RGB9E5Float': (3, 4, 4), |
| + 'B5G6R5Unorm': (3, 2, 2), |
| + 'A1BGR5Unorm': (4, 2, 2), |
| + 'ABGR4Unorm': (4, 2, 2), |
| + 'BGR5A1Unorm': (4, 2, 2), |
| + } |
| + predefined = predefined_formats.get(base_name) |
| + if predefined: |
| + return predefined |
| + |
| + # Regular formats: [channels][bits][type] |
| + # e.g. R8Unorm, RG16Float, RGBA32Uint, BGRA8Unorm, A8Unorm |
| + m = re.match(r'^(A|RGBA|BGRA|BGR|RGB|RG|R)(\d+)(Unorm|Snorm|Uint|Sint|Float)$', base_name) |
| + assert m |
| + |
| + channels = len(m.group(1)) |
| + bits = int(m.group(2)) |
| + bytes_per_channel = bits // 8 |
| + pixel_bytes = channels * bytes_per_channel |
| + alignment = pixel_bytes // channels |
| + return channels, pixel_bytes, alignment |
| + |
| # NOTE(hqle): This is a modified version of the get_vertex_copy_function() function in |
| # src/libANGLE/renderer/angle_format.py |
| # - Return value is a tuple {copy_function, default_alpha_value, have_same_gl_type}. |
| @@ -720,22 +791,36 @@ def gen_mtl_format_caps_init_string(map_image): |
| ios_specific_caps = map_image['caps_ios_specific'] |
| caps_init_str = '' |
| |
| - def cap_to_param(caps, key): |
| - return '/** ' + key + '*/ ' + caps.get(key, 'false') |
| - |
| def caps_to_cpp(caps_table): |
| init_str = '' |
| # Tracks whether the pixel format family being added to `init_str` is deprecated. |
| section_contains_deprecated_format = False |
| for mtl_format in sorted(caps_table.keys()): |
| + if is_format_compressed(mtl_format): |
| + compressed = 'true' |
| + pixel_bytes = 0 |
| + pixel_bytes_msaa = 0 |
| + channels = 0 |
| + alignment = 0 |
| + else: |
| + compressed = 'false' |
| + channels, pixel_bytes, alignment = get_mtl_format_info(mtl_format) |
| + pixel_bytes_msaa = pixel_bytes |
| + |
| caps = caps_table[mtl_format] |
| - filterable = cap_to_param(caps, 'filterable') |
| - writable = cap_to_param(caps, 'writable') |
| - colorRenderable = cap_to_param(caps, 'colorRenderable') |
| - depthRenderable = cap_to_param(caps, 'depthRenderable') |
| - blendable = cap_to_param(caps, 'blendable') |
| - multisample = cap_to_param(caps, 'multisample') |
| - resolve = cap_to_param(caps, 'resolve') |
| + |
| + filterable = caps.get('filterable', 'false') |
| + writable = caps.get('writable', 'false') |
| + color_renderable = caps.get('colorRenderable', 'false') |
| + depth_renderable = caps.get('depthRenderable', 'false') |
| + blendable = caps.get('blendable', 'false') |
| + multisample = caps.get('multisample', 'false') |
| + resolve = caps.get('resolve', 'false') |
| + compressed = caps.get('compressed', compressed) |
| + pixel_bytes = caps.get('pixelBytes', pixel_bytes) |
| + pixel_bytes_msaa = caps.get('pixelBytes', pixel_bytes_msaa) |
| + channels = caps.get('channels', channels) |
| + alignment = caps.get('alignment', alignment) |
| |
| # Add deprecation warnings around MTLPixelFormatPVRTC_* enums. |
| format_is_deprecated = is_format_deprecated(mtl_format) |
| @@ -743,9 +828,21 @@ def gen_mtl_format_caps_init_string(map_image): |
| format_is_deprecated, section_contains_deprecated_format) |
| section_contains_deprecated_format = format_is_deprecated |
| |
| - init_str += " setFormatCaps({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7});\n\n".format( |
| - mtl_format, filterable, writable, blendable, multisample, resolve, colorRenderable, |
| - depthRenderable) |
| + init_str += f""" setFormatCaps({mtl_format}, |
| + {{ |
| + .filterable = {filterable}, |
| + .writable = {writable}, |
| + .colorRenderable = {color_renderable}, |
| + .depthRenderable = {depth_renderable}, |
| + .blendable = {blendable}, |
| + .multisample = {multisample}, |
| + .resolve = {resolve}, |
| + .compressed = {compressed}, |
| + .pixelBytes = {pixel_bytes}, |
| + .pixelBytesMSAA = {pixel_bytes}, |
| + .channels = {channels}, |
| + .alignment = {alignment} |
| + }});\n""" |
| |
| return init_str |
| |
| diff --git a/src/libANGLE/renderer/metal/mtl_command_buffer.h b/src/libANGLE/renderer/metal/mtl_command_buffer.h |
| index 443f2e4cca4e9d59a5a28ad55e77a301215442ee..c12cd5a37c39030d9bda10ac553bf127281ae079 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_command_buffer.h |
| +++ b/src/libANGLE/renderer/metal/mtl_command_buffer.h |
| @@ -126,6 +126,8 @@ class CommandQueue final : public WrappedObject<id<MTLCommandQueue>>, angle::Non |
| double getTimeElapsedEntryInSeconds(uint64_t id); |
| MTLCommandBufferError popCmdBufferError() { return mCmdBufferError.pop(); } |
| |
| + bool isDeviceLost() const { return mIsDeviceLost; } |
| + |
| private: |
| using ParentClass = WrappedObject<id<MTLCommandQueue>>; |
| |
| @@ -176,6 +178,8 @@ class CommandQueue final : public WrappedObject<id<MTLCommandQueue>>, angle::Non |
| AtomicCommandBufferError mCmdBufferError; |
| |
| angle::HashMap<uint64_t, std::vector<std::function<void()>>> mCommandBufferScheduledCallbacks; |
| + |
| + std::atomic_bool mIsDeviceLost = false; |
| }; |
| |
| class CommandBuffer final : public WrappedObject<id<MTLCommandBuffer>>, angle::NonCopyable |
| @@ -449,8 +453,9 @@ class RenderCommandEncoder final : public CommandEncoder |
| RenderCommandEncoder &setStencilRefVals(uint32_t frontRef, uint32_t backRef); |
| RenderCommandEncoder &setStencilRefVal(uint32_t ref); |
| |
| - RenderCommandEncoder &setViewport(const MTLViewport &viewport); |
| - RenderCommandEncoder &setScissorRect(const MTLScissorRect &rect); |
| + RenderCommandEncoder &setViewport(const MTLViewport &viewport, id<MTLRasterizationRateMap> map); |
| + RenderCommandEncoder &setScissorRect(const MTLScissorRect &rect, |
| + id<MTLRasterizationRateMap> map); |
| |
| RenderCommandEncoder &setBlendColor(float r, float g, float b, float a); |
| |
| @@ -597,6 +602,8 @@ class RenderCommandEncoder final : public CommandEncoder |
| RenderCommandEncoder &setDepthLoadAction(MTLLoadAction action, double clearValue); |
| RenderCommandEncoder &setStencilLoadAction(MTLLoadAction action, uint32_t clearValue); |
| |
| + RenderCommandEncoder &setRasterizationRateMap(id<MTLRasterizationRateMap> map); |
| + |
| void setLabel(NSString *label); |
| |
| void pushDebugGroup(NSString *label) override; |
| @@ -604,8 +611,11 @@ class RenderCommandEncoder final : public CommandEncoder |
| |
| const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; } |
| bool hasDrawCalls() const { return mHasDrawCalls; } |
| + bool hasPipelineState() const { return mPipelineStateSet; } |
| |
| uint64_t getSerial() const { return mSerial; } |
| + id<MTLRasterizationRateMap> rasterizationRateMapForPass(id<MTLRasterizationRateMap> map, |
| + id<MTLTexture> colorTexture) const; |
| |
| private: |
| // Override CommandEncoder |
| diff --git a/src/libANGLE/renderer/metal/mtl_command_buffer.mm b/src/libANGLE/renderer/metal/mtl_command_buffer.mm |
| index 0decccbae0f34bbe511a186886e74ba08a8e5a4d..3934b7d2f8ff27444e1500c29bd3405c59b2cce7 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_command_buffer.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_command_buffer.mm |
| @@ -694,6 +694,18 @@ void CommandQueue::onCommandBufferCompleted(id<MTLCommandBuffer> buf, |
| << error.localizedDescription.UTF8String; |
| mCmdBufferError.store(static_cast<MTLCommandBufferError>(error.code)); |
| } |
| + MTLCommandBufferStatus status = buf.status; |
| + if (status != MTLCommandBufferStatusCompleted) |
| + { |
| + // MTLCommandBufferErrorNotPermitted is non-fatal, all other errors |
| + // result in device lost. |
| + // TODO(djg): Should this also check error.domain for MTLCommandBufferErrorDomain? |
| + mIsDeviceLost = !error || error.code != MTLCommandBufferErrorNotPermitted; |
| + if (mIsDeviceLost) |
| + { |
| + return; |
| + } |
| + } |
| |
| if (timeElapsedEntry != 0) |
| { |
| @@ -1405,6 +1417,7 @@ void RenderCommandEncoder::reset() |
| CommandEncoder::reset(); |
| mRecording = false; |
| mPipelineStateSet = false; |
| + setRasterizationRateMap(nil); |
| mCommands.clear(); |
| } |
| |
| @@ -1440,7 +1453,7 @@ bool RenderCommandEncoder::finalizeLoadStoreAction( |
| } |
| |
| // Check if we need to disable MTLLoadActionLoad & MTLStoreActionStore |
| - mtl::TextureRef mainTextureRef = cppRenderPassAttachment.getImplicitMSTextureIfAvailOrTexture(); |
| + mtl::TextureRef mainTextureRef = cppRenderPassAttachment.texture; |
| ASSERT(mainTextureRef->get() == objCRenderPassAttachment.texture); |
| if (mainTextureRef->shouldNotLoadStore()) |
| { |
| @@ -1584,13 +1597,13 @@ void RenderCommandEncoder::endEncodingImpl(bool considerDiscardSimulation) |
| inline void RenderCommandEncoder::initAttachmentWriteDependencyAndScissorRect( |
| const RenderPassAttachmentDesc &attachment) |
| { |
| - TextureRef texture = attachment.texture; |
| + auto texture = attachment.hasResolveTexture() ? attachment.resolveTexture : attachment.texture; |
| + auto &mipLevel = attachment.hasResolveTexture() ? attachment.resolveLevel : attachment.level; |
| + |
| if (texture) |
| { |
| cmdBuffer().setWriteDependency(texture, /*isRenderCommand=*/true); |
| |
| - const MipmapNativeLevel &mipLevel = attachment.level; |
| - |
| mRenderPassMaxScissorRect.width = |
| std::min<NSUInteger>(mRenderPassMaxScissorRect.width, texture->width(mipLevel)); |
| mRenderPassMaxScissorRect.height = |
| @@ -1868,7 +1881,8 @@ RenderCommandEncoder &RenderCommandEncoder::setStencilRefVal(uint32_t ref) |
| return setStencilRefVals(ref, ref); |
| } |
| |
| -RenderCommandEncoder &RenderCommandEncoder::setViewport(const MTLViewport &viewport) |
| +RenderCommandEncoder &RenderCommandEncoder::setViewport(const MTLViewport &viewport, |
| + id<MTLRasterizationRateMap> map) |
| { |
| if (mStateCache.viewport.valid() && mStateCache.viewport.value() == viewport) |
| { |
| @@ -1881,12 +1895,25 @@ RenderCommandEncoder &RenderCommandEncoder::setViewport(const MTLViewport &viewp |
| return *this; |
| } |
| |
| -RenderCommandEncoder &RenderCommandEncoder::setScissorRect(const MTLScissorRect &rect) |
| +RenderCommandEncoder &RenderCommandEncoder::setScissorRect(const MTLScissorRect &rect, |
| + id<MTLRasterizationRateMap> map) |
| { |
| + auto maxScissorRect = |
| + MTLCoordinate2DMake(mRenderPassMaxScissorRect.width, mRenderPassMaxScissorRect.height); |
| + |
| + if (map) |
| + { |
| + maxScissorRect = [map mapPhysicalToScreenCoordinates:maxScissorRect forLayer:0]; |
| + if (!(rect.width * rect.height)) |
| + { |
| + return *this; |
| + } |
| + } |
| + |
| NSUInteger clampedWidth = |
| - rect.x > mRenderPassMaxScissorRect.width ? 0 : mRenderPassMaxScissorRect.width - rect.x; |
| + rect.x > maxScissorRect.x ? 0 : (NSUInteger)ceilf(maxScissorRect.x) - rect.x; |
| NSUInteger clampedHeight = |
| - rect.y > mRenderPassMaxScissorRect.height ? 0 : mRenderPassMaxScissorRect.height - rect.y; |
| + rect.y > maxScissorRect.y ? 0 : (NSUInteger)ceilf(maxScissorRect.y) - rect.y; |
| |
| MTLScissorRect clampedRect = {rect.x, rect.y, std::min(rect.width, clampedWidth), |
| std::min(rect.height, clampedHeight)}; |
| @@ -1898,6 +1925,25 @@ RenderCommandEncoder &RenderCommandEncoder::setScissorRect(const MTLScissorRect |
| |
| mStateCache.scissorRect = clampedRect; |
| |
| + if (map) |
| + { |
| + auto adjustedOrigin = |
| + [map mapPhysicalToScreenCoordinates:MTLCoordinate2DMake(clampedRect.x, clampedRect.y) |
| + forLayer:0]; |
| + auto adjustedSize = |
| + [map mapPhysicalToScreenCoordinates:MTLCoordinate2DMake(clampedRect.width, |
| + clampedRect.height) |
| + forLayer:0]; |
| + |
| + clampedRect.x = (NSUInteger)roundf(adjustedOrigin.x); |
| + clampedRect.y = (NSUInteger)roundf(adjustedOrigin.y); |
| + MTLSize screenSize = [map screenSize]; |
| + clampedRect.width = |
| + std::min(screenSize.width, static_cast<NSUInteger>(roundf(adjustedSize.x))); |
| + clampedRect.height = |
| + std::min(screenSize.height, static_cast<NSUInteger>(roundf(adjustedSize.y))); |
| + } |
| + |
| mCommands.push(CmdType::SetScissorRect).push(clampedRect); |
| |
| return *this; |
| @@ -2303,6 +2349,20 @@ void RenderCommandEncoder::popDebugGroup() |
| mCommands.push(CmdType::PopDebugGroup); |
| } |
| |
| +id<MTLRasterizationRateMap> RenderCommandEncoder::rasterizationRateMapForPass( |
| + id<MTLRasterizationRateMap> map, |
| + id<MTLTexture> texture) const |
| +{ |
| + if (!mCachedRenderPassDescObjC.get()) |
| + { |
| + return nil; |
| + } |
| + |
| + MTLSize size = [map physicalSizeForLayer:0]; |
| + id<MTLTexture> t = mCachedRenderPassDescObjC.get().colorAttachments[0].texture; |
| + return t.width == size.width && t.height == size.height ? map : nil; |
| +} |
| + |
| RenderCommandEncoder &RenderCommandEncoder::setColorStoreAction(MTLStoreAction action, |
| uint32_t colorAttachmentIndex) |
| { |
| @@ -2398,6 +2458,16 @@ RenderCommandEncoder &RenderCommandEncoder::setStencilLoadAction(MTLLoadAction a |
| return *this; |
| } |
| |
| +RenderCommandEncoder &RenderCommandEncoder::setRasterizationRateMap(id<MTLRasterizationRateMap> map) |
| +{ |
| + if (map != mCachedRenderPassDescObjC.get().rasterizationRateMap) |
| + { |
| + mCachedRenderPassDescObjC.get().rasterizationRateMap = map; |
| + } |
| + |
| + return *this; |
| +} |
| + |
| void RenderCommandEncoder::setLabel(NSString *label) |
| { |
| mLabel = std::move(label); |
| diff --git a/src/libANGLE/renderer/metal/mtl_common.h b/src/libANGLE/renderer/metal/mtl_common.h |
| index 85cc743533100d7b9c7b33c343047f4e4576aa48..d9a22279750932bce8298cc5ffa0d909bd53c7f9 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_common.h |
| +++ b/src/libANGLE/renderer/metal/mtl_common.h |
| @@ -95,10 +95,6 @@ constexpr uint32_t kMaxRenderTargets = 8; |
| // Metal Apple1 iOS devices only support 4 render targets |
| constexpr uint32_t kMaxRenderTargetsOlderGPUFamilies = 4; |
| |
| -constexpr uint32_t kMaxColorTargetBitsApple1To3 = 256; |
| -constexpr uint32_t kMaxColorTargetBitsApple4Plus = 512; |
| -constexpr uint32_t kMaxColorTargetBitsMacAndCatalyst = std::numeric_limits<uint32_t>::max(); |
| - |
| constexpr uint32_t kMaxShaderUBOs = 16; |
| constexpr uint32_t kMaxUBOSize = 16384; |
| |
| diff --git a/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm b/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm |
| index 7ec88c5fde46b8c0e3fca7fdaf70616cdea46ece..2eaa347787b990ed402ca8ec6687ad648ca759f4 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm |
| @@ -3872,635 +3872,1997 @@ void FormatTable::initNativeFormatCapsAutogen(const DisplayMtl *display) |
| bool supportDepthStencilAutoResolve = supportDepthAutoResolve && supportStencilAutoResolve; |
| |
| // Source: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf |
| - setFormatCaps(MTLPixelFormatA8Unorm, /** filterable*/ true, /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatBGR10A2Unorm, /** filterable*/ true, |
| - /** writable*/ display->supportsEitherGPUFamily(3, 1), /** blendable*/ true, |
| - /** multisample*/ true, /** resolve*/ true, /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatBGRA8Unorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatBGRA8Unorm_sRGB, /** filterable*/ true, |
| - /** writable*/ display->supportsAppleGPUFamily(2) && !display->isSimulator(), |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| + // clang-format off |
| + setFormatCaps(MTLPixelFormatA8Unorm, |
| + { |
| + .filterable = true, |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 1, |
| + .pixelBytesMSAA = 1, |
| + .channels = 1, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatBGR10A2Unorm, |
| + { |
| + .filterable = true, |
| + .writable = display->supportsEitherGPUFamily(3, 1), |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatBGRA8Unorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatBGRA8Unorm_sRGB, |
| + { |
| + .filterable = true, |
| + .writable = display->supportsAppleGPUFamily(2) && !display->isSimulator(), |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 1 |
| + }); |
| setFormatCaps(MTLPixelFormatDepth32Float, |
| - /** filterable*/ display->supports32BitFloatFiltering(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ true, |
| - /** resolve*/ supportDepthAutoResolve, /** colorRenderable*/ false, |
| - /** depthRenderable*/ true); |
| - |
| + { |
| + .filterable = display->supports32BitFloatFiltering(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = true, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = supportDepthAutoResolve, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 0, |
| + .alignment = 4 |
| + }); |
| setFormatCaps(MTLPixelFormatDepth32Float_Stencil8, |
| - /** filterable*/ display->supports32BitFloatFiltering(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ true, |
| - /** resolve*/ supportDepthStencilAutoResolve, /** colorRenderable*/ false, |
| - /** depthRenderable*/ true); |
| - |
| - setFormatCaps(MTLPixelFormatR16Float, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR16Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR16Snorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsMacGPUFamily(1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR16Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR16Unorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsMacGPUFamily(1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps( |
| - MTLPixelFormatR32Float, |
| - /** filterable*/ display->supportsMacGPUFamily(1) || |
| - (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| - /** writable*/ true, /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsMacGPUFamily(1) || |
| - (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR32Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ display->supportsMacGPUFamily(1), |
| - /** resolve*/ false, /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR32Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ display->supportsMacGPUFamily(1), |
| - /** resolve*/ false, /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR8Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR8Snorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsEitherGPUFamily(2, 1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR8Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatR8Unorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG11B10Float, /** filterable*/ true, |
| - /** writable*/ display->supportsEitherGPUFamily(3, 1), /** blendable*/ true, |
| - /** multisample*/ true, /** resolve*/ true, /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG16Float, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG16Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG16Snorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsMacGPUFamily(1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG16Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG16Unorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsMacGPUFamily(1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps( |
| - MTLPixelFormatRG32Float, |
| - /** filterable*/ display->supportsMacGPUFamily(1) || |
| - (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| - /** writable*/ true, /** blendable*/ true, |
| - /** multisample*/ display->supportsEitherGPUFamily(7, 1), |
| - /** resolve*/ display->supportsMacGPUFamily(1) || |
| - (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG32Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ display->supportsEitherGPUFamily(7, 1), |
| - /** resolve*/ false, /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG32Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ display->supportsEitherGPUFamily(7, 1), |
| - /** resolve*/ false, /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG8Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG8Snorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsEitherGPUFamily(2, 1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG8Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG8Unorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGB10A2Uint, /** filterable*/ false, |
| - /** writable*/ display->supportsEitherGPUFamily(3, 1), /** blendable*/ false, |
| - /** multisample*/ true, /** resolve*/ false, /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGB10A2Unorm, /** filterable*/ true, |
| - /** writable*/ display->supportsEitherGPUFamily(3, 1), /** blendable*/ true, |
| - /** multisample*/ true, /** resolve*/ true, /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps( |
| - MTLPixelFormatRGB9E5Float, /** filterable*/ true, |
| - /** writable*/ display->supportsAppleGPUFamily(3), |
| - /** blendable*/ display->supportsAppleGPUFamily(1), |
| - /** multisample*/ display->supportsAppleGPUFamily(1), |
| - /** resolve*/ display->supportsAppleGPUFamily(1), |
| - /** colorRenderable*/ display->supportsAppleGPUFamily(1) && !display->isSimulator(), |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA16Float, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA16Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA16Snorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsMacGPUFamily(1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA16Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA16Unorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsMacGPUFamily(1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps( |
| - MTLPixelFormatRGBA32Float, |
| - /** filterable*/ display->supportsMacGPUFamily(1) || |
| - (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| - /** writable*/ true, |
| - /** blendable*/ display->supportsMacGPUFamily(1) || |
| - (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| - /** multisample*/ display->supportsEitherGPUFamily(7, 1), |
| - /** resolve*/ display->supportsMacGPUFamily(1) || |
| - (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA32Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ display->supportsMacGPUFamily(1), |
| - /** resolve*/ false, /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA32Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ display->supportsMacGPUFamily(1), |
| - /** resolve*/ false, /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA8Sint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA8Snorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, |
| - /** resolve*/ display->supportsEitherGPUFamily(2, 1), /** colorRenderable*/ true, |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA8Uint, /** filterable*/ false, /** writable*/ true, |
| - /** blendable*/ false, /** multisample*/ true, /** resolve*/ false, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA8Unorm, /** filterable*/ true, /** writable*/ true, |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRGBA8Unorm_sRGB, /** filterable*/ true, |
| - /** writable*/ display->supportsAppleGPUFamily(2) && !display->isSimulator(), |
| - /** blendable*/ true, /** multisample*/ true, /** resolve*/ true, |
| - /** colorRenderable*/ true, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatStencil8, /** filterable*/ false, /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ true, |
| - /** resolve*/ supportStencilAutoResolve, /** colorRenderable*/ false, |
| - /** depthRenderable*/ true); |
| - |
| -#if TARGET_OS_OSX || TARGET_OS_MACCATALYST || \ |
| - (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400) || \ |
| + { |
| + .filterable = display->supports32BitFloatFiltering(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = true, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = supportDepthStencilAutoResolve, |
| + .compressed = false, |
| + .pixelBytes = 5, |
| + .pixelBytesMSAA = 5, |
| + .channels = 0, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatR16Float, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 1, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatR16Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 1, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatR16Snorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsMacGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 1, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatR16Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 1, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatR16Unorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsMacGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 1, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatR32Float, |
| + { |
| + .filterable = display->supportsMacGPUFamily(1) || (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsMacGPUFamily(1) || (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 1, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatR32Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = display->supportsMacGPUFamily(1), |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 1, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatR32Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = display->supportsMacGPUFamily(1), |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 1, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatR8Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 1, |
| + .pixelBytesMSAA = 1, |
| + .channels = 1, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatR8Snorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsEitherGPUFamily(2, 1), |
| + .compressed = false, |
| + .pixelBytes = 1, |
| + .pixelBytesMSAA = 1, |
| + .channels = 1, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatR8Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 1, |
| + .pixelBytesMSAA = 1, |
| + .channels = 1, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatR8Unorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 1, |
| + .pixelBytesMSAA = 1, |
| + .channels = 1, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG11B10Float, |
| + { |
| + .filterable = true, |
| + .writable = display->supportsEitherGPUFamily(3, 1), |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 3, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG16Float, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 2, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG16Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 2, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG16Snorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsMacGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 2, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG16Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 2, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG16Unorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsMacGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 2, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG32Float, |
| + { |
| + .filterable = display->supportsMacGPUFamily(1) || (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = display->supportsEitherGPUFamily(7, 1), |
| + .resolve = display->supportsMacGPUFamily(1) || (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 2, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG32Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = display->supportsEitherGPUFamily(7, 1), |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 2, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG32Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = display->supportsEitherGPUFamily(7, 1), |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 2, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG8Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 2, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG8Snorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsEitherGPUFamily(2, 1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 2, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG8Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 2, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG8Unorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 2, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGB10A2Uint, |
| + { |
| + .filterable = false, |
| + .writable = display->supportsEitherGPUFamily(3, 1), |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGB10A2Unorm, |
| + { |
| + .filterable = true, |
| + .writable = display->supportsEitherGPUFamily(3, 1), |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGB9E5Float, |
| + { |
| + .filterable = true, |
| + .writable = display->supportsAppleGPUFamily(3), |
| + .colorRenderable = display->supportsAppleGPUFamily(1) && !display->isSimulator(), |
| + .depthRenderable = false, |
| + .blendable = display->supportsAppleGPUFamily(1), |
| + .multisample = display->supportsAppleGPUFamily(1), |
| + .resolve = display->supportsAppleGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 3, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA16Float, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA16Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA16Snorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsMacGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA16Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA16Unorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsMacGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 8, |
| + .pixelBytesMSAA = 8, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA32Float, |
| + { |
| + .filterable = display->supportsMacGPUFamily(1) || (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = display->supportsMacGPUFamily(1) || (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| + .multisample = display->supportsEitherGPUFamily(7, 1), |
| + .resolve = display->supportsMacGPUFamily(1) || (display->supportsAppleGPUFamily(7) && display->supports32BitFloatFiltering()), |
| + .compressed = false, |
| + .pixelBytes = 16, |
| + .pixelBytesMSAA = 16, |
| + .channels = 4, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA32Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = display->supportsMacGPUFamily(1), |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 16, |
| + .pixelBytesMSAA = 16, |
| + .channels = 4, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA32Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = display->supportsMacGPUFamily(1), |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 16, |
| + .pixelBytesMSAA = 16, |
| + .channels = 4, |
| + .alignment = 4 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA8Sint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA8Snorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = display->supportsEitherGPUFamily(2, 1), |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA8Uint, |
| + { |
| + .filterable = false, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = false, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA8Unorm, |
| + { |
| + .filterable = true, |
| + .writable = true, |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRGBA8Unorm_sRGB, |
| + { |
| + .filterable = true, |
| + .writable = display->supportsAppleGPUFamily(2) && !display->isSimulator(), |
| + .colorRenderable = true, |
| + .depthRenderable = false, |
| + .blendable = true, |
| + .multisample = true, |
| + .resolve = true, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 4, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatStencil8, |
| + { |
| + .filterable = false, |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = true, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = supportStencilAutoResolve, |
| + .compressed = false, |
| + .pixelBytes = 1, |
| + .pixelBytesMSAA = 1, |
| + .channels = 0, |
| + .alignment = 1 |
| + }); |
| +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST ||\ |
| + (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400) ||\ |
| (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 160400) || TARGET_OS_VISION |
| - setFormatCaps(MTLPixelFormatBC1_RGBA, /** filterable*/ display->supportsBCTextureCompression(), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + setFormatCaps(MTLPixelFormatBC1_RGBA, |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC1_RGBA_sRGB, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatBC2_RGBA, /** filterable*/ display->supportsBCTextureCompression(), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatBC2_RGBA, |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC2_RGBA_sRGB, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatBC3_RGBA, /** filterable*/ display->supportsBCTextureCompression(), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatBC3_RGBA, |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC3_RGBA_sRGB, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC4_RSnorm, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC4_RUnorm, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC5_RGSnorm, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC5_RGUnorm, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC6H_RGBFloat, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC6H_RGBUfloat, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC7_RGBAUnorm, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatBC7_RGBAUnorm_sRGB, |
| - /** filterable*/ display->supportsBCTextureCompression(), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsBCTextureCompression(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| #endif // BC formats |
| #if TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| - setFormatCaps(MTLPixelFormatDepth16Unorm, /** filterable*/ true, /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ true, |
| - /** resolve*/ supportDepthAutoResolve, /** colorRenderable*/ false, |
| - /** depthRenderable*/ true); |
| - |
| + setFormatCaps(MTLPixelFormatDepth16Unorm, |
| + { |
| + .filterable = true, |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = true, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = supportDepthAutoResolve, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 0, |
| + .alignment = 2 |
| + }); |
| setFormatCaps(MTLPixelFormatDepth24Unorm_Stencil8, |
| - /** filterable*/ display->supportsMacGPUFamily(1) && |
| - display->supportsDepth24Stencil8PixelFormat(), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ true, |
| - /** resolve*/ supportDepthStencilAutoResolve, /** colorRenderable*/ false, |
| - /** depthRenderable*/ display->supportsMacGPUFamily(1) && |
| - display->supportsDepth24Stencil8PixelFormat()); |
| - |
| + { |
| + .filterable = display->supportsMacGPUFamily(1) && display->supportsDepth24Stencil8PixelFormat(), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = display->supportsMacGPUFamily(1) && display->supportsDepth24Stencil8PixelFormat(), |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = supportDepthStencilAutoResolve, |
| + .compressed = false, |
| + .pixelBytes = 4, |
| + .pixelBytesMSAA = 4, |
| + .channels = 0, |
| + .alignment = 4 |
| + }); |
| #endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| #if (TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST) || \ |
| (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000)) |
| - setFormatCaps(MTLPixelFormatA1BGR5Unorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ display->supportsAppleGPUFamily(1), |
| - /** multisample*/ display->supportsAppleGPUFamily(1), |
| - /** resolve*/ display->supportsAppleGPUFamily(1), |
| - /** colorRenderable*/ display->supportsAppleGPUFamily(1), |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatABGR4Unorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ display->supportsAppleGPUFamily(1), |
| - /** multisample*/ display->supportsAppleGPUFamily(1), |
| - /** resolve*/ display->supportsAppleGPUFamily(1), |
| - /** colorRenderable*/ display->supportsAppleGPUFamily(1), |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x10_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + setFormatCaps(MTLPixelFormatA1BGR5Unorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = display->supportsAppleGPUFamily(1), |
| + .depthRenderable = false, |
| + .blendable = display->supportsAppleGPUFamily(1), |
| + .multisample = display->supportsAppleGPUFamily(1), |
| + .resolve = display->supportsAppleGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatABGR4Unorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = display->supportsAppleGPUFamily(1), |
| + .depthRenderable = false, |
| + .blendable = display->supportsAppleGPUFamily(1), |
| + .multisample = display->supportsAppleGPUFamily(1), |
| + .resolve = display->supportsAppleGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x10_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatASTC_10x10_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(2), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x5_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x5_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x6_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x6_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x8_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x8_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_12x10_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x5_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x5_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x6_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x6_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x8_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x8_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_12x10_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatASTC_12x10_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(2), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_12x12_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_12x12_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatASTC_12x12_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(2), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_4x4_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_4x4_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_5x4_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_5x4_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_5x5_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_5x5_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_6x5_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_6x5_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_6x6_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_6x6_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x5_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x5_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x6_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x6_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x8_LDR, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x8_sRGB, /** filterable*/ display->supportsAppleGPUFamily(2), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatB5G6R5Unorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ display->supportsAppleGPUFamily(1), |
| - /** multisample*/ display->supportsAppleGPUFamily(1), |
| - /** resolve*/ display->supportsAppleGPUFamily(1), |
| - /** colorRenderable*/ display->supportsAppleGPUFamily(1), |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatBGR5A1Unorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ display->supportsAppleGPUFamily(1), |
| - /** multisample*/ display->supportsAppleGPUFamily(1), |
| - /** resolve*/ display->supportsAppleGPUFamily(1), |
| - /** colorRenderable*/ display->supportsAppleGPUFamily(1), |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatDepth16Unorm, /** filterable*/ true, /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ true, |
| - /** resolve*/ supportDepthAutoResolve, /** colorRenderable*/ false, |
| - /** depthRenderable*/ true); |
| - |
| - setFormatCaps(MTLPixelFormatEAC_R11Snorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatEAC_R11Unorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatEAC_RG11Snorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatEAC_RG11Unorm, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatEAC_RGBA8, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatEAC_RGBA8_sRGB, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatETC2_RGB8, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatETC2_RGB8A1, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_4x4_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_4x4_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_5x4_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_5x4_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_5x5_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_5x5_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_6x5_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_6x5_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_6x6_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_6x6_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x5_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x5_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x6_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x6_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x8_LDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x8_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(2), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatB5G6R5Unorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = display->supportsAppleGPUFamily(1), |
| + .depthRenderable = false, |
| + .blendable = display->supportsAppleGPUFamily(1), |
| + .multisample = display->supportsAppleGPUFamily(1), |
| + .resolve = display->supportsAppleGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 3, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatBGR5A1Unorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = display->supportsAppleGPUFamily(1), |
| + .depthRenderable = false, |
| + .blendable = display->supportsAppleGPUFamily(1), |
| + .multisample = display->supportsAppleGPUFamily(1), |
| + .resolve = display->supportsAppleGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 4, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatDepth16Unorm, |
| + { |
| + .filterable = true, |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = true, |
| + .blendable = false, |
| + .multisample = true, |
| + .resolve = supportDepthAutoResolve, |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 0, |
| + .alignment = 2 |
| + }); |
| + setFormatCaps(MTLPixelFormatEAC_R11Snorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatEAC_R11Unorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatEAC_RG11Snorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatEAC_RG11Unorm, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatEAC_RGBA8, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatEAC_RGBA8_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatETC2_RGB8, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatETC2_RGB8A1, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatETC2_RGB8A1_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(1), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatETC2_RGB8_sRGB, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| -# pragma clang diagnostic push |
| -# pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatETC2_RGB8_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| +#pragma clang diagnostic push |
| +#pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| setFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP, |
| - /** filterable*/ display->supportsAppleGPUFamily(1), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatPVRTC_RGBA_2BPP_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(1), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP, |
| - /** filterable*/ display->supportsAppleGPUFamily(1), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatPVRTC_RGBA_4BPP_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(1), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatPVRTC_RGB_2BPP_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(1), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| setFormatCaps(MTLPixelFormatPVRTC_RGB_4BPP_sRGB, |
| - /** filterable*/ display->supportsAppleGPUFamily(1), /** writable*/ false, |
| - /** blendable*/ false, /** multisample*/ false, /** resolve*/ false, |
| - /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| -# pragma clang diagnostic pop |
| - setFormatCaps(MTLPixelFormatR8Unorm_sRGB, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ display->supportsAppleGPUFamily(2), |
| - /** blendable*/ display->supportsAppleGPUFamily(1), |
| - /** multisample*/ display->supportsAppleGPUFamily(1), |
| - /** resolve*/ display->supportsAppleGPUFamily(1), |
| - /** colorRenderable*/ display->supportsAppleGPUFamily(1), |
| - /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatRG8Unorm_sRGB, /** filterable*/ display->supportsAppleGPUFamily(1), |
| - /** writable*/ display->supportsAppleGPUFamily(2), |
| - /** blendable*/ display->supportsAppleGPUFamily(1), |
| - /** multisample*/ display->supportsAppleGPUFamily(1), |
| - /** resolve*/ display->supportsAppleGPUFamily(1), |
| - /** colorRenderable*/ display->supportsAppleGPUFamily(1), |
| - /** depthRenderable*/ false); |
| - |
| -# if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_VISION |
| - setFormatCaps(MTLPixelFormatASTC_10x10_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x5_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x6_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_10x8_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_12x10_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_12x12_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_4x4_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_5x4_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_5x5_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_6x5_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_6x6_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x5_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| - |
| - setFormatCaps(MTLPixelFormatASTC_8x6_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| +#pragma clang diagnostic pop |
| + setFormatCaps(MTLPixelFormatR8Unorm_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = display->supportsAppleGPUFamily(2), |
| + .colorRenderable = display->supportsAppleGPUFamily(1), |
| + .depthRenderable = false, |
| + .blendable = display->supportsAppleGPUFamily(1), |
| + .multisample = display->supportsAppleGPUFamily(1), |
| + .resolve = display->supportsAppleGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 1, |
| + .pixelBytesMSAA = 1, |
| + .channels = 1, |
| + .alignment = 1 |
| + }); |
| + setFormatCaps(MTLPixelFormatRG8Unorm_sRGB, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(1), |
| + .writable = display->supportsAppleGPUFamily(2), |
| + .colorRenderable = display->supportsAppleGPUFamily(1), |
| + .depthRenderable = false, |
| + .blendable = display->supportsAppleGPUFamily(1), |
| + .multisample = display->supportsAppleGPUFamily(1), |
| + .resolve = display->supportsAppleGPUFamily(1), |
| + .compressed = false, |
| + .pixelBytes = 2, |
| + .pixelBytesMSAA = 2, |
| + .channels = 2, |
| + .alignment = 1 |
| + }); |
| +#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_VISION |
| + setFormatCaps(MTLPixelFormatASTC_10x10_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x5_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x6_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_10x8_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_12x10_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_12x12_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_4x4_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_5x4_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_5x5_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_6x5_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_6x6_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x5_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x6_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| + setFormatCaps(MTLPixelFormatASTC_8x8_HDR, |
| + { |
| + .filterable = display->supportsAppleGPUFamily(6), |
| + .writable = false, |
| + .colorRenderable = false, |
| + .depthRenderable = false, |
| + .blendable = false, |
| + .multisample = false, |
| + .resolve = false, |
| + .compressed = true, |
| + .pixelBytes = 0, |
| + .pixelBytesMSAA = 0, |
| + .channels = 0, |
| + .alignment = 0 |
| + }); |
| +#endif // TARGET_OS_IOS || mac 11.0+ || TARGET_OS_VISION |
| +#endif // TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST || mac 11.0+ |
| |
| - setFormatCaps(MTLPixelFormatASTC_8x8_HDR, /** filterable*/ display->supportsAppleGPUFamily(6), |
| - /** writable*/ false, /** blendable*/ false, /** multisample*/ false, |
| - /** resolve*/ false, /** colorRenderable*/ false, /** depthRenderable*/ false); |
| + // clang-format on |
| |
| -# endif // TARGET_OS_IOS || mac 11.0+ || TARGET_OS_VISION |
| -#endif // TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST || mac 11.0+ |
| +#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) |
| + const bool supportsiOS2 = SupportsAppleGPUFamily(display->getMetalDevice(), 2); |
| + const bool supportsiOS4 = SupportsAppleGPUFamily(display->getMetalDevice(), 4); |
| + for (auto &entry : mNativePixelFormatCapsTable) |
| + { |
| + adjustFormatCapsForDevice(entry.first, supportsiOS2, supportsiOS4); |
| + } |
| +#endif |
| } |
| |
| } // namespace mtl |
| diff --git a/src/libANGLE/renderer/metal/mtl_format_utils.h b/src/libANGLE/renderer/metal/mtl_format_utils.h |
| index db95298598177500cebd0eb81cfcb845656031b2..6902e5756f34f420e0e126f6b7f897962615fa03 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_format_utils.h |
| +++ b/src/libANGLE/renderer/metal/mtl_format_utils.h |
| @@ -89,6 +89,10 @@ struct Format : public FormatBase |
| // Need conversion between source format and this format? |
| bool needConversion(angle::FormatID srcFormatId) const; |
| |
| + // Are the formats view compatible without requiring |
| + // MTLTextureUsagePixelFormatView? |
| + bool isViewCompatible(const Format &srcFormat) const; |
| + |
| MTLPixelFormat metalFormat = MTLPixelFormatInvalid; |
| |
| LoadFunctionMap textureLoadFunctions = nullptr; |
| @@ -150,50 +154,9 @@ class FormatTable final : angle::NonCopyable |
| void initNativeFormatCapsAutogen(const DisplayMtl *display); |
| void initNativeFormatCaps(const DisplayMtl *display); |
| |
| - void setFormatCaps(MTLPixelFormat formatId, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable); |
| - |
| - void setFormatCaps(MTLPixelFormat formatId, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable, |
| - NSUInteger bytesPerChannel, |
| - NSUInteger channels); |
| - |
| - void setFormatCaps(MTLPixelFormat formatId, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable, |
| - bool depthRenderable); |
| - |
| - void setFormatCaps(MTLPixelFormat formatId, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable, |
| - bool depthRenderable, |
| - NSUInteger bytesPerChannel, |
| - NSUInteger channels); |
| - |
| - void setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable); |
| - |
| - void adjustFormatCapsForDevice(const mtl::ContextDevice &device, |
| - MTLPixelFormat id, |
| - bool supportsiOS2, |
| - bool supportsiOS4); |
| + void setFormatCaps(MTLPixelFormat formatId, const FormatCaps &caps); |
| + |
| + void adjustFormatCapsForDevice(MTLPixelFormat id, bool supportsiOS2, bool supportsiOS4); |
| |
| std::array<Format, angle::kNumANGLEFormats> mPixelFormatTable; |
| angle::HashMap<MTLPixelFormat, FormatCaps> mNativePixelFormatCapsTable; |
| diff --git a/src/libANGLE/renderer/metal/mtl_format_utils.mm b/src/libANGLE/renderer/metal/mtl_format_utils.mm |
| index 0c6aba022ec6f39a897e1ab596d24c7fafcd316f..9201ca9c9711010a69174af34e4c96f462784b12 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_format_utils.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_format_utils.mm |
| @@ -165,6 +165,34 @@ bool Format::needConversion(angle::FormatID srcFormatId) const |
| return srcFormatId != actualFormatId; |
| } |
| |
| +bool Format::isViewCompatible(const Format &srcFormat) const |
| +{ |
| + if (srcFormat.metalFormat == metalFormat) |
| + { |
| + return true; |
| + } |
| + |
| + // The pixel layout is considered different if the number of components differs, |
| + if (srcFormat.caps.channels != caps.channels) |
| + { |
| + return false; |
| + } |
| + |
| + // ... or if their size or order is different from the components in the original pixel format. |
| + if (srcFormat.caps.pixelBytes != caps.pixelBytes) |
| + { |
| + return false; |
| + } |
| + |
| + // This is overly conservative but reject compressed formats |
| + if (srcFormat.caps.compressed || caps.compressed) |
| + { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| bool Format::isPVRTC() const |
| { |
| // Suppress `MTLPixelFormatPVRTC_*` deprecation warnings. |
| @@ -244,79 +272,12 @@ const VertexFormat &FormatTable::getVertexFormat(angle::FormatID angleFormatId, |
| return mVertexFormatTables[tableIdx][static_cast<size_t>(angleFormatId)]; |
| } |
| |
| -void FormatTable::setFormatCaps(MTLPixelFormat formatId, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable) |
| -{ |
| - setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable, |
| - false, 0); |
| -} |
| -void FormatTable::setFormatCaps(MTLPixelFormat formatId, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable, |
| - NSUInteger pixelBytes, |
| - NSUInteger channels) |
| -{ |
| - setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable, |
| - false, pixelBytes, channels); |
| -} |
| - |
| -void FormatTable::setFormatCaps(MTLPixelFormat formatId, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable, |
| - bool depthRenderable) |
| -{ |
| - setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable, |
| - depthRenderable, 0, 0); |
| -} |
| -void FormatTable::setFormatCaps(MTLPixelFormat id, |
| - bool filterable, |
| - bool writable, |
| - bool blendable, |
| - bool multisample, |
| - bool resolve, |
| - bool colorRenderable, |
| - bool depthRenderable, |
| - NSUInteger pixelBytes, |
| - NSUInteger channels) |
| -{ |
| - mNativePixelFormatCapsTable[id].filterable = filterable; |
| - mNativePixelFormatCapsTable[id].writable = writable; |
| - mNativePixelFormatCapsTable[id].colorRenderable = colorRenderable; |
| - mNativePixelFormatCapsTable[id].depthRenderable = depthRenderable; |
| - mNativePixelFormatCapsTable[id].blendable = blendable; |
| - mNativePixelFormatCapsTable[id].multisample = multisample; |
| - mNativePixelFormatCapsTable[id].resolve = resolve; |
| - mNativePixelFormatCapsTable[id].pixelBytes = pixelBytes; |
| - mNativePixelFormatCapsTable[id].pixelBytesMSAA = pixelBytes; |
| - mNativePixelFormatCapsTable[id].channels = channels; |
| - if (channels != 0) |
| - { |
| - mNativePixelFormatCapsTable[id].alignment = MAX(pixelBytes / channels, 1U); |
| - } |
| -} |
| - |
| -void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable) |
| +void FormatTable::setFormatCaps(MTLPixelFormat formatId, const FormatCaps &caps) |
| { |
| - setFormatCaps(formatId, filterable, false, false, false, false, false, false); |
| + mNativePixelFormatCapsTable[formatId] = caps; |
| } |
| |
| -void FormatTable::adjustFormatCapsForDevice(const mtl::ContextDevice &device, |
| - MTLPixelFormat id, |
| - bool supportsiOS2, |
| - bool supportsiOS4) |
| +void FormatTable::adjustFormatCapsForDevice(MTLPixelFormat id, bool supportsiOS2, bool supportsiOS4) |
| { |
| #if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST) |
| |
| diff --git a/src/libANGLE/renderer/metal/mtl_pipeline_cache.mm b/src/libANGLE/renderer/metal/mtl_pipeline_cache.mm |
| index f39b822294b6ed18db734dec45bf200307574802..6d73b0b57a32c33bdd186b186afcdf34b7039988 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_pipeline_cache.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_pipeline_cache.mm |
| @@ -76,17 +76,22 @@ angle::Result ValidateRenderPipelineState(ContextMtl *context, |
| GL_INVALID_OPERATION); |
| } |
| |
| - // Ensure the device can support the storage requirement for render targets. |
| - if (DeviceHasMaximumRenderTargetSize(device)) |
| + const std::optional<NSUInteger> maxSize = |
| + mtl::GetMaxRenderPassColorSizeBytes(context->getDisplay()->getFeatures(), device); |
| + if (maxSize) |
| { |
| - NSUInteger maxSize = GetMaxRenderTargetSizeForDeviceInBytes(device); |
| NSUInteger renderTargetSize = |
| ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(descriptor, context, device); |
| - if (renderTargetSize > maxSize) |
| + if (renderTargetSize > *maxSize) |
| { |
| + // Unreachable: FramebufferMtl::checkStatus rejects color-attachment |
| + // configurations whose total byte size exceeds this device's |
| + // budget, so the pipeline-time check is defensive only. |
| + UNREACHABLE(); |
| std::stringstream errorStream; |
| errorStream << "This set of render targets requires " << renderTargetSize |
| - << " bytes of pixel storage. This device supports " << maxSize << " bytes."; |
| + << " bytes of pixel storage. This device supports " << *maxSize |
| + << " bytes."; |
| ANGLE_CHECK(context, false, errorStream.str().c_str(), GL_INVALID_OPERATION); |
| } |
| } |
| diff --git a/src/libANGLE/renderer/metal/mtl_render_utils.mm b/src/libANGLE/renderer/metal/mtl_render_utils.mm |
| index 2b1af8d9a1cd6e5c0bd9919aefa3d2673208b103..3e9ea580c1ad9b7585a6ac9008639cdc3f374213 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_render_utils.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_render_utils.mm |
| @@ -533,6 +533,27 @@ RenderPipelineDesc GetComputingVertexShaderOnlyRenderPipelineDesc(RenderCommandE |
| return pipelineDesc; |
| } |
| |
| +// Find the largest power-of-two threadgroup width that won't overflow uint32_t after rounding. |
| +// Metal's thread_position_in_grid is uint32_t, so numGroups * width must not exceed UINT32_MAX. |
| + |
| +// FIXME: For optimal GPU efficiency, large dispatches should be broken into multiple smaller |
| +// dispatches rather than reducing threadgroup width. |
| +NSUInteger SafeThreadgroupWidth(size_t numThreads, NSUInteger maxWidth) |
| +{ |
| + NSUInteger threadgroupWidth = std::clamp<NSUInteger>(numThreads, 1u, maxWidth); |
| + while (threadgroupWidth > 1) |
| + { |
| + size_t numGroups = (numThreads + threadgroupWidth - 1) / threadgroupWidth; |
| + size_t roundedThreads = numGroups * threadgroupWidth; |
| + if (roundedThreads <= std::numeric_limits<uint32_t>::max()) |
| + { |
| + break; |
| + } |
| + threadgroupWidth >>= 1; |
| + } |
| + return threadgroupWidth; |
| +} |
| + |
| // Dispatch compute using 3D grid |
| void DispatchCompute(ContextMtl *contextMtl, |
| ComputeCommandEncoder *encoder, |
| @@ -560,8 +581,13 @@ void DispatchCompute(ContextMtl *contextMtl, |
| id<MTLComputePipelineState> pipelineState, |
| size_t numThreads) |
| { |
| - NSUInteger w = std::min<NSUInteger>(pipelineState.threadExecutionWidth, numThreads); |
| - MTLSize threadsPerThreadgroup = MTLSizeMake(w, 1, 1); |
| + ASSERT(numThreads != 0); |
| + |
| + // Use safe threadgroup width to prevent overflow after rounding. Metal validates that |
| + // the rounded grid size (numGroups * threadgroupWidth) fits in uint32_t, even for |
| + // non-uniform dispatch which internally rounds up to threadgroup boundaries. |
| + NSUInteger safeWidth = SafeThreadgroupWidth(numThreads, pipelineState.threadExecutionWidth); |
| + MTLSize threadsPerThreadgroup = MTLSizeMake(safeWidth, 1, 1); |
| |
| if (contextMtl->getDisplay()->getFeatures().hasNonUniformDispatch.enabled) |
| { |
| @@ -570,7 +596,7 @@ void DispatchCompute(ContextMtl *contextMtl, |
| } |
| else |
| { |
| - MTLSize groups = MTLSizeMake((numThreads + w - 1) / w, 1, 1); |
| + MTLSize groups = MTLSizeMake((numThreads + safeWidth - 1) / safeWidth, 1, 1); |
| cmdEncoder->dispatch(groups, threadsPerThreadgroup); |
| } |
| } |
| @@ -640,8 +666,9 @@ void SetupCommonBlitWithDrawStates(const gl::Context *context, |
| GetViewport(params.dstRect, params.dstTextureSize.height, params.dstFlipY); |
| MTLScissorRect scissorRectMtl = |
| GetScissorRect(params.dstScissorRect, params.dstTextureSize.height, params.dstFlipY); |
| - cmdEncoder->setViewport(viewportMtl); |
| - cmdEncoder->setScissorRect(scissorRectMtl); |
| + |
| + cmdEncoder->setViewport(viewportMtl, nil); |
| + cmdEncoder->setScissorRect(scissorRectMtl, nil); |
| |
| if (params.src) |
| { |
| @@ -1111,8 +1138,8 @@ angle::Result ClearUtils::setupClearWithDraw(const gl::Context *context, |
| |
| scissorRect = GetScissorRect(params.clearArea, params.dstTextureSize.height, params.flipY); |
| |
| - cmdEncoder->setViewport(viewport); |
| - cmdEncoder->setScissorRect(scissorRect); |
| + cmdEncoder->setViewport(viewport, nil); |
| + cmdEncoder->setScissorRect(scissorRect, nil); |
| |
| // uniform |
| ClearParamsUniform uniformParams; |
| @@ -2476,8 +2503,8 @@ angle::Result CopyPixelsUtils::unpackPixelsWithDraw(const gl::Context *context, |
| |
| scissorRect = GetScissorRect(rect); |
| |
| - cmdEncoder->setViewport(viewport); |
| - cmdEncoder->setScissorRect(scissorRect); |
| + cmdEncoder->setViewport(viewport, nil); |
| + cmdEncoder->setScissorRect(scissorRect, nil); |
| |
| // uniform |
| CopyPixelFromBufferUniforms options; |
| diff --git a/src/libANGLE/renderer/metal/mtl_resource_spi.h b/src/libANGLE/renderer/metal/mtl_resource_spi.h |
| index 3eaa9a64e79af26faa786102ece3f0bdea84d090..7ecb6db9d993df8985fcb6f701dfe7ca75857cae 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_resource_spi.h |
| +++ b/src/libANGLE/renderer/metal/mtl_resource_spi.h |
| @@ -1,9 +1,63 @@ |
| -// |
| -// Copyright 2021 The ANGLE Project Authors. All rights reserved. |
| -// Use of this source code is governed by a BSD-style license that can be |
| -// found in the LICENSE file. |
| +/* |
| + * Copyright (C) 2021 Apple Inc. All rights reserved. |
| + * |
| + * Redistribution and use in source and binary forms, with or without |
| + * modification, are permitted provided that the following conditions |
| + * are met: |
| + * 1. Redistributions of source code must retain the above copyright |
| + * notice, this list of conditions and the following disclaimer. |
| + * 2. Redistributions in binary form must reproduce the above copyright |
| + * notice, this list of conditions and the following disclaimer in the |
| + * documentation and/or other materials provided with the distribution. |
| + * |
| + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| + * THE POSSIBILITY OF SUCH DAMAGE. |
| + */ |
| + |
| // |
| // mtl_resource_spi.h: |
| -// Used to set Metal resource ownership identity with SPI. |
| -// Purposefully empty header file. Actual implementation will be hosted in WebKit. |
| +// Used to set Metal resource ownership identity with SPI |
| // |
| + |
| +#ifndef LIBANGLE_RENDERER_METAL_RESOURCE_SPI_H_ |
| +#define LIBANGLE_RENDERER_METAL_RESOURCE_SPI_H_ |
| + |
| +#import "common/apple/apple_platform.h" |
| + |
| +#if ANGLE_USE_METAL_OWNERSHIP_IDENTITY |
| + |
| +# import <Metal/MTLResource_Private.h> |
| +# import <Metal/Metal.h> |
| +# import <mach/mach_types.h> |
| + |
| +namespace rx |
| +{ |
| +namespace mtl |
| +{ |
| +inline void setOwnerWithIdentity(id<MTLResource> resource, task_id_token_t identityToken) |
| +{ |
| + if (identityToken != TASK_ID_TOKEN_NULL) |
| + { |
| + kern_return_t kr = [(id<MTLResourceSPI>)resource setOwnerWithIdentity:identityToken]; |
| + if (ANGLE_UNLIKELY(kr != KERN_SUCCESS)) |
| + { |
| + ERR() << "setOwnerWithIdentity failed with: %s (%x)" << mach_error_string(kr) << kr; |
| + ASSERT(false); |
| + } |
| + } |
| + return; |
| +} |
| +} // namespace mtl |
| +} // namespace rx |
| +#endif |
| + |
| +#endif /* LIBANGLE_RENDERER_METAL_RESOURCE_SPI_H_ */ |
| diff --git a/src/libANGLE/renderer/metal/mtl_resources.h b/src/libANGLE/renderer/metal/mtl_resources.h |
| index 8916375318715e32e360189b1996fd96b8c005cc..4be593e59d56e075a29157980776c25000c99c83 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_resources.h |
| +++ b/src/libANGLE/renderer/metal/mtl_resources.h |
| @@ -256,6 +256,11 @@ class Texture final : public Resource, |
| TextureRef createCubeFaceView(uint32_t face); |
| // Create a view of one slice at a level. |
| TextureRef createSliceMipView(uint32_t slice, const MipmapNativeLevel &level); |
| + // Same as createSliceMipView but the target format must be compatible, for example sRGB to |
| + // linear. In this case texture doesn't need format view usage flag. |
| + TextureRef createSliceMipViewWithCompatibleFormat(uint32_t slice, |
| + const MipmapNativeLevel &level, |
| + MTLPixelFormat format); |
| // Create a levels range view |
| TextureRef createMipsView(const MipmapNativeLevel &baseLevel, uint32_t levels); |
| // Create a view of a level. |
| diff --git a/src/libANGLE/renderer/metal/mtl_resources.mm b/src/libANGLE/renderer/metal/mtl_resources.mm |
| index d9187406a8e0593f61ac7124daec58bbd2f6a592..d21e2b73ff57cc26f5196b3f3702c44b2fe28dfb 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_resources.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_resources.mm |
| @@ -83,12 +83,10 @@ MTLResourceOptions resourceOptionsForStorageMode(MTLStorageMode storageMode) |
| return MTLResourceStorageModePrivate; |
| case MTLStorageModeMemoryless: |
| return MTLResourceStorageModeMemoryless; |
| -#if TARGET_OS_SIMULATOR |
| default: |
| // TODO(http://anglebug.com/42266474): Remove me once hacked SDKs are fixed. |
| UNREACHABLE(); |
| return MTLResourceStorageModeShared; |
| -#endif |
| } |
| } |
| |
| @@ -718,7 +716,9 @@ TextureRef Texture::createCubeFaceView(uint32_t face) |
| } |
| } |
| |
| -TextureRef Texture::createSliceMipView(uint32_t slice, const MipmapNativeLevel &level) |
| +TextureRef Texture::createSliceMipViewWithCompatibleFormat(uint32_t slice, |
| + const MipmapNativeLevel &level, |
| + MTLPixelFormat format) |
| { |
| ANGLE_MTL_OBJC_SCOPE |
| { |
| @@ -727,7 +727,7 @@ TextureRef Texture::createSliceMipView(uint32_t slice, const MipmapNativeLevel & |
| case MTLTextureTypeCube: |
| case MTLTextureType2D: |
| case MTLTextureType2DArray: |
| - return TextureRef(new Texture(this, pixelFormat(), MTLTextureType2D, |
| + return TextureRef(new Texture(this, format, MTLTextureType2D, |
| NSMakeRange(level.get(), 1), NSMakeRange(slice, 1))); |
| default: |
| UNREACHABLE(); |
| @@ -736,6 +736,11 @@ TextureRef Texture::createSliceMipView(uint32_t slice, const MipmapNativeLevel & |
| } |
| } |
| |
| +TextureRef Texture::createSliceMipView(uint32_t slice, const MipmapNativeLevel &level) |
| +{ |
| + return createSliceMipViewWithCompatibleFormat(slice, level, pixelFormat()); |
| +} |
| + |
| TextureRef Texture::createMipView(const MipmapNativeLevel &level) |
| { |
| ANGLE_MTL_OBJC_SCOPE |
| diff --git a/src/libANGLE/renderer/metal/mtl_state_cache.h b/src/libANGLE/renderer/metal/mtl_state_cache.h |
| index 9f4d0c54f33a0be77a8f2e89de894865c14ea02c..237f625d0806b0453e18636976d48fbde3611cba 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_state_cache.h |
| +++ b/src/libANGLE/renderer/metal/mtl_state_cache.h |
| @@ -652,20 +652,21 @@ struct RenderPassAttachmentDesc |
| bool equalIgnoreLoadStoreOptions(const RenderPassAttachmentDesc &other) const; |
| bool operator==(const RenderPassAttachmentDesc &other) const; |
| |
| - ANGLE_INLINE bool hasImplicitMSTexture() const { return implicitMSTexture.get(); } |
| - |
| - const TextureRef &getImplicitMSTextureIfAvailOrTexture() const |
| - { |
| - return hasImplicitMSTexture() ? implicitMSTexture : texture; |
| - } |
| + ANGLE_INLINE bool hasResolveTexture() const { return resolveTexture.get(); } |
| |
| + // When rendering with implicit multisample, |texture| is the texture that |
| + // will be rendered into and discarded at the end of a render pass. Its |
| + // result will be automatically resolved into |resolveTexture|. |
| TextureRef texture; |
| // Implicit multisample texture that will be rendered into and discarded at the end of |
| // a render pass. Its result will be resolved into normal texture above. |
| - TextureRef implicitMSTexture; |
| + TextureRef resolveTexture; |
| MipmapNativeLevel level = mtl::kZeroNativeMipLevel; |
| uint32_t sliceOrDepth = 0; |
| |
| + MipmapNativeLevel resolveLevel; |
| + uint32_t resolveSliceOrDepth; |
| + |
| // This attachment is blendable or not. |
| bool blendable = false; |
| MTLLoadAction loadAction = MTLLoadActionLoad; |
| diff --git a/src/libANGLE/renderer/metal/mtl_state_cache.mm b/src/libANGLE/renderer/metal/mtl_state_cache.mm |
| index 5c6d88f7c418bb1641c6d8722d45a9815b94ab84..909bb2cead2236969e9440748051c331817898d3 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_state_cache.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_state_cache.mm |
| @@ -134,44 +134,29 @@ id<MTLTexture> ToObjC(const TextureRef &texture) |
| void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src, |
| MTLRenderPassAttachmentDescriptor *dst) |
| { |
| - const TextureRef &implicitMsTexture = src.implicitMSTexture; |
| - |
| - if (implicitMsTexture) |
| - { |
| - dst.texture = ToObjC(implicitMsTexture); |
| - dst.level = 0; |
| - dst.slice = 0; |
| - dst.depthPlane = 0; |
| - dst.resolveTexture = ToObjC(src.texture); |
| - dst.resolveLevel = src.level.get(); |
| - if (dst.resolveTexture.textureType == MTLTextureType3D) |
| - { |
| - dst.resolveDepthPlane = src.sliceOrDepth; |
| - dst.resolveSlice = 0; |
| - } |
| - else |
| - { |
| - dst.resolveSlice = src.sliceOrDepth; |
| - dst.resolveDepthPlane = 0; |
| - } |
| - } |
| - else |
| - { |
| dst.texture = ToObjC(src.texture); |
| dst.level = src.level.get(); |
| if (dst.texture.textureType == MTLTextureType3D) |
| { |
| - dst.depthPlane = src.sliceOrDepth; |
| dst.slice = 0; |
| + dst.depthPlane = src.sliceOrDepth; |
| } |
| else |
| { |
| dst.slice = src.sliceOrDepth; |
| dst.depthPlane = 0; |
| } |
| - dst.resolveTexture = nil; |
| - dst.resolveLevel = 0; |
| + |
| + dst.resolveTexture = ToObjC(src.resolveTexture); |
| + dst.resolveLevel = src.resolveLevel.get(); |
| + if (dst.resolveTexture.textureType == MTLTextureType3D) |
| + { |
| dst.resolveSlice = 0; |
| + dst.resolveDepthPlane = src.resolveSliceOrDepth; |
| + } |
| + else |
| + { |
| + dst.resolveSlice = src.resolveSliceOrDepth; |
| dst.resolveDepthPlane = 0; |
| } |
| |
| @@ -472,7 +457,7 @@ angle::ObjCPtr<MTLRenderPipelineDescriptor> RenderPipelineDesc::createMetalDesc( |
| bool RenderPassAttachmentDesc::equalIgnoreLoadStoreOptions( |
| const RenderPassAttachmentDesc &other) const |
| { |
| - return texture == other.texture && implicitMSTexture == other.implicitMSTexture && |
| + return texture == other.texture && resolveTexture == other.resolveTexture && |
| level == other.level && sliceOrDepth == other.sliceOrDepth && |
| blendable == other.blendable; |
| } |
| diff --git a/src/libANGLE/renderer/metal/mtl_utils.h b/src/libANGLE/renderer/metal/mtl_utils.h |
| index ee49da99d0db03368d09c73f311633818c057684..b3221004c9943f67fa3f08ecef925e4d493f756f 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_utils.h |
| +++ b/src/libANGLE/renderer/metal/mtl_utils.h |
| @@ -13,6 +13,8 @@ |
| |
| #import <Metal/Metal.h> |
| |
| +#include <optional> |
| + |
| #include "angle_gl.h" |
| #include "common/MemoryBuffer.h" |
| #include "common/PackedEnums.h" |
| @@ -175,9 +177,7 @@ size_t EstimateTextureSizeInBytes(const mtl::Format &mtlFormat, |
| size_t sampleCount, |
| size_t numMips); |
| |
| -NSUInteger GetMaxRenderTargetSizeForDeviceInBytes(const mtl::ContextDevice &device); |
| NSUInteger GetMaxNumberOfRenderTargetsForDevice(const mtl::ContextDevice &device); |
| -bool DeviceHasMaximumRenderTargetSize(id<MTLDevice> device); |
| |
| // Useful to set clear color for texture originally having no alpha in GL, but backend's format |
| // has alpha channel. |
| @@ -192,6 +192,12 @@ NSUInteger ComputeTotalSizeUsedForMTLRenderPipelineDescriptor( |
| const Context *context, |
| const mtl::ContextDevice &device); |
| |
| +// Returns the device's max render-pass color byte budget, or nullopt when the |
| +// device imposes no fixed limit (e.g. macOS). Honors |
| +// FeaturesMtl::limitMaxColorTargetBitsForTesting. |
| +std::optional<NSUInteger> GetMaxRenderPassColorSizeBytes(const angle::FeaturesMtl &features, |
| + const mtl::ContextDevice &device); |
| + |
| gl::Rectangle MTLRegionToGLRect(const MTLRegion &mtlRegion); |
| gl::Box MTLRegionToGLBox(const MTLRegion &mtlRegion); |
| |
| diff --git a/src/libANGLE/renderer/metal/mtl_utils.mm b/src/libANGLE/renderer/metal/mtl_utils.mm |
| index 63ff329ef1cdcdf07233be29cedecbeea9995047..7cd2a9a5dd309557b5edaf109e8f5894352ce5d4 100644 |
| --- a/src/libANGLE/renderer/metal/mtl_utils.mm |
| +++ b/src/libANGLE/renderer/metal/mtl_utils.mm |
| @@ -412,21 +412,19 @@ bool PreferStagedTextureUploads(const gl::Context *context, |
| const Format &textureObjFormat, |
| StagingPurpose purpose) |
| { |
| - // The simulator MUST upload all textures as staged. |
| - if (TARGET_OS_SIMULATOR) |
| - { |
| - return true; |
| - } |
| - |
| - ContextMtl *contextMtl = mtl::GetImpl(context); |
| - const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures(); |
| - |
| + // Compressed textures cannot be uploaded from staging textures. |
| const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat(); |
| if (intendedInternalFormat.compressed || textureObjFormat.actualAngleFormat().isBlock) |
| { |
| return false; |
| } |
| |
| + // The simulator MUST upload all non-compressed textures as staged. |
| + if (TARGET_OS_SIMULATOR) |
| + { |
| + return true; |
| + } |
| + |
| // If the intended internal format is luminance, we can still |
| // initialize the texture using the GPU. However, if we're |
| // uploading data to it, we avoid using a staging buffer, due to |
| @@ -439,6 +437,9 @@ bool PreferStagedTextureUploads(const gl::Context *context, |
| return (purpose == StagingPurpose::Initialization); |
| } |
| |
| + ContextMtl *contextMtl = mtl::GetImpl(context); |
| + const angle::FeaturesMtl &features = contextMtl->getDisplay()->getFeatures(); |
| + |
| if (features.disableStagedInitializationOfPackedTextureFormats.enabled) |
| { |
| switch (intendedInternalFormat.sizedInternalFormat) |
| @@ -1356,22 +1357,6 @@ MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask col |
| return re; |
| } |
| |
| -NSUInteger GetMaxRenderTargetSizeForDeviceInBytes(const mtl::ContextDevice &device) |
| -{ |
| - if (SupportsAppleGPUFamily(device, 4)) |
| - { |
| - return 64; |
| - } |
| - else if (SupportsAppleGPUFamily(device, 2)) |
| - { |
| - return 32; |
| - } |
| - else |
| - { |
| - return 16; |
| - } |
| -} |
| - |
| NSUInteger GetMaxNumberOfRenderTargetsForDevice(const mtl::ContextDevice &device) |
| { |
| if (SupportsAppleGPUFamily(device, 2) || SupportsMacGPUFamily(device, 1)) |
| @@ -1384,11 +1369,6 @@ NSUInteger GetMaxNumberOfRenderTargetsForDevice(const mtl::ContextDevice &device |
| } |
| } |
| |
| -bool DeviceHasMaximumRenderTargetSize(id<MTLDevice> device) |
| -{ |
| - return !SupportsMacGPUFamily(device, 1); |
| -} |
| - |
| bool SupportsAppleGPUFamily(id<MTLDevice> device, uint8_t appleFamily) |
| { |
| MTLGPUFamily family; |
| @@ -1421,6 +1401,24 @@ bool SupportsAppleGPUFamily(id<MTLDevice> device, uint8_t appleFamily) |
| return [device supportsFamily:family]; |
| } |
| |
| +#if (defined(__MAC_13_0) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_13_0) || \ |
| + (defined(__IPHONE_16_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_16_0) || \ |
| + (defined(__TVOS_16_0) && __TV_OS_VERSION_MIN_REQUIRED >= __TVOS_16_0) |
| +# define ANGLE_MTL_FEATURE_SET_DEPRECATED 1 |
| +# define ANGLE_MTL_GPU_FAMILY_MAC1_DEPRECATED 1 |
| +#endif |
| + |
| +#if ANGLE_MTL_GPU_FAMILY_MAC1_DEPRECATED |
| +# define ANGLE_MTL_GPU_FAMILY_MAC1 MTLGPUFamilyMac2 |
| +# define ANGLE_MTL_GPU_FAMILY_MAC2 MTLGPUFamilyMac2 |
| +#elif TARGET_OS_MACCATALYST |
| +# define ANGLE_MTL_GPU_FAMILY_MAC1 MTLGPUFamilyMacCatalyst1 |
| +# define ANGLE_MTL_GPU_FAMILY_MAC2 MTLGPUFamilyMacCatalyst2 |
| +#else // !ANGLE_MTL_GPU_FAMILY_MAC1_DEPRECATED && !TARGET_OS_MACCATALYST |
| +# define ANGLE_MTL_GPU_FAMILY_MAC1 MTLGPUFamilyMac1 |
| +# define ANGLE_MTL_GPU_FAMILY_MAC2 MTLGPUFamilyMac2 |
| +#endif |
| + |
| bool SupportsMacGPUFamily(id<MTLDevice> device, uint8_t macFamily) |
| { |
| #if TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| @@ -1466,13 +1464,12 @@ static NSUInteger getNextLocationForAttachment(const mtl::RenderPassAttachmentDe |
| const Context *context, |
| NSUInteger currentRenderTargetSize) |
| { |
| - mtl::TextureRef texture = |
| - attachment.implicitMSTexture ? attachment.implicitMSTexture : attachment.texture; |
| + mtl::TextureRef texture = attachment.texture; |
| |
| if (texture) |
| { |
| MTLPixelFormat pixelFormat = texture->pixelFormat(); |
| - bool isMsaa = texture->samples(); |
| + bool isMsaa = texture->samples() > 1; |
| const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(pixelFormat); |
| currentRenderTargetSize = getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize); |
| } |
| @@ -1490,19 +1487,6 @@ NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const mtl::RenderPassD |
| currentRenderTargetSize = getNextLocationForAttachment(descriptor.colorAttachments[i], |
| context, currentRenderTargetSize); |
| } |
| - if (descriptor.depthAttachment.texture == descriptor.stencilAttachment.texture) |
| - { |
| - currentRenderTargetSize = getNextLocationForAttachment(descriptor.depthAttachment, context, |
| - currentRenderTargetSize); |
| - } |
| - else |
| - { |
| - currentRenderTargetSize = getNextLocationForAttachment(descriptor.depthAttachment, context, |
| - currentRenderTargetSize); |
| - currentRenderTargetSize = getNextLocationForAttachment(descriptor.stencilAttachment, |
| - context, currentRenderTargetSize); |
| - } |
| - |
| return currentRenderTargetSize; |
| } |
| |
| @@ -1523,34 +1507,33 @@ NSUInteger ComputeTotalSizeUsedForMTLRenderPipelineDescriptor( |
| getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize); |
| } |
| } |
| - if (descriptor.depthAttachmentPixelFormat == descriptor.stencilAttachmentPixelFormat) |
| - { |
| - if (descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid) |
| + return currentRenderTargetSize; |
| +} |
| + |
| +std::optional<NSUInteger> GetMaxRenderPassColorSizeBytes(const angle::FeaturesMtl &features, |
| + const mtl::ContextDevice &device) |
| +{ |
| + if (features.limitMaxColorTargetBitsForTesting.enabled) |
| { |
| - const FormatCaps &caps = |
| - context->getDisplay()->getNativeFormatCaps(descriptor.depthAttachmentPixelFormat); |
| - currentRenderTargetSize = |
| - getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize); |
| - } |
| + return 32; |
| } |
| - else |
| + if (SupportsMacGPUFamily(device, 1)) |
| { |
| - if (descriptor.depthAttachmentPixelFormat != MTLPixelFormatInvalid) |
| + return std::nullopt; |
| + } |
| + if (SupportsAppleGPUFamily(device, 7)) |
| { |
| - const FormatCaps &caps = |
| - context->getDisplay()->getNativeFormatCaps(descriptor.depthAttachmentPixelFormat); |
| - currentRenderTargetSize = |
| - getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize); |
| + return 128; |
| } |
| - if (descriptor.stencilAttachmentPixelFormat != MTLPixelFormatInvalid) |
| + if (SupportsAppleGPUFamily(device, 4)) |
| { |
| - const FormatCaps &caps = |
| - context->getDisplay()->getNativeFormatCaps(descriptor.stencilAttachmentPixelFormat); |
| - currentRenderTargetSize = |
| - getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize); |
| + return 64; |
| } |
| + if (SupportsAppleGPUFamily(device, 2)) |
| + { |
| + return 32; |
| } |
| - return currentRenderTargetSize; |
| + return 16; |
| } |
| |
| gl::Rectangle MTLRegionToGLRect(const MTLRegion &mtlRegion) |
| diff --git a/src/libANGLE/renderer/metal/shaders/create_mtl_internal_shaders.py b/src/libANGLE/renderer/metal/shaders/create_mtl_internal_shaders.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..23e8295bcc16412d3aef3fc8e85748fa4ad77a70 |
| --- /dev/null |
| +++ b/src/libANGLE/renderer/metal/shaders/create_mtl_internal_shaders.py |
| @@ -0,0 +1,65 @@ |
| +#!/usr/bin/python3 |
| +# Copyright 2021 The ANGLE Project Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| +# |
| +# create_mtl_internal_shaders.py: |
| +# Script to compile a metalLib into NSData, for including the compilded |
| +# library in the ANGLE dylib. |
| + |
| +import os |
| +import sys |
| +import json |
| +from datetime import datetime |
| + |
| +sys.path.append('../..') |
| + |
| +template_header_boilerplate = """// GENERATED FILE - DO NOT EDIT. |
| +// Generated by {script_name} |
| +// |
| +// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| +// |
| +""" |
| + |
| + |
| +# Convert content of a file to byte array and store in a header file. |
| +# variable_name: name of C++ variable that will hold the file content as byte array. |
| +# filename: the file whose content will be converted to C++ byte array. |
| +# dest_src_file: destination header file that will contain the byte array. |
| +def append_file_as_byte_array_string(variable_name, filename, dest_src_file): |
| + string = '// Generated from {0}:\n'.format(filename) |
| + string += 'constexpr uint8_t {0}[]={{\n'.format(variable_name) |
| + bytes_ = open(filename, "rb").read() |
| + for byte in bytes_: |
| + string += '0x{:02x}'.format(byte) + ", " |
| + string += "\n};\n" |
| + with open(dest_src_file, "a") as out_file: |
| + out_file.write(string) |
| + |
| + |
| +def main(): |
| + input_file = sys.argv[1] |
| + output_file = sys.argv[2] |
| + os.chdir(sys.path[0]) |
| + |
| + boilerplate_code = template_header_boilerplate.format( |
| + script_name=os.path.basename(sys.argv[0]), copyright_year=datetime.today().year) |
| + |
| + # -------- Compile shaders ----------- |
| + # boiler plate code |
| + os.system("echo \"{0}\" > \"{1}\"".format(boilerplate_code, output_file)) |
| + os.system( |
| + 'echo "// Compiled binary for Metal default shaders.\n\n" >> \"{0}\"'.format(output_file)) |
| + os.system('echo "#include <TargetConditionals.h>\n\n" >> \"{0}\"'.format(output_file)) |
| + |
| + os.system('echo "// clang-format off" >> \"{0}\"'.format(output_file)) |
| + |
| + append_file_as_byte_array_string('gDefaultMetallib', input_file, output_file) |
| + |
| + os.system('echo "// clang-format on" >> \"{0}\"'.format(output_file)) |
| + |
| + |
| +if __name__ == '__main__': |
| + sys.exit(main()) |
| diff --git a/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_autogen.metal b/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_autogen.metal |
| index c1b01286a6e9e599518f0b53dc0055e3d5ff2beb..d2a18c989407209aca146dcf613e68b295606ce0 100644 |
| --- a/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_autogen.metal |
| +++ b/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_autogen.metal |
| @@ -2549,10 +2549,10 @@ constant bool outIndexBufferIsUint16 = (((fixIndexBufferKey >> 2U) & 0x03U) == 2 |
| constant bool outIndexBufferIsUint32 = (((fixIndexBufferKey >> 2U) & 0x03U) == 3U); |
| constant bool doPrimRestart = (fixIndexBufferKey & 0x00100U); |
| constant uint fixIndexBufferMode = (fixIndexBufferKey >> 4U) & 0x0FU; |
| +constant uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF; |
| static inline uint readIdx( |
| const device ushort *indexBufferUint16, |
| const device uint *indexBufferUint32, |
| - const uint restartIndex, |
| const uint indexCount, |
| uint idx, |
| thread bool &foundRestart, |
| @@ -2588,7 +2588,6 @@ static inline void outputPrimitive( |
| const device uint *indexBufferUint32, |
| device ushort *outIndexBufferUint16, |
| device uint *outIndexBufferUint32, |
| - const uint restartIndex, |
| const uint indexCount, |
| thread uint &baseIndex, |
| uint onIndex, |
| @@ -2602,7 +2601,7 @@ static inline void outputPrimitive( |
| { |
| case 0x00U: |
| { |
| - auto tmpIndex = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2614,8 +2613,8 @@ static inline void outputPrimitive( |
| break; |
| case 0x01U: |
| { |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2643,8 +2642,8 @@ static inline void outputPrimitive( |
| break; |
| case 0x03U: |
| { |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2666,9 +2665,9 @@ static inline void outputPrimitive( |
| break; |
| case 0x04U: |
| { |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2701,9 +2700,9 @@ static inline void outputPrimitive( |
| case 0x05U: |
| { |
| uint isOdd = ((onIndex - baseIndex) & 1); |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0 + isOdd, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1 - isOdd, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0 + isOdd, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1 - isOdd, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2748,7 +2747,6 @@ kernel void fixIndexBuffer( |
| constant uint &primCount [[ buffer(3) ]], |
| uint prim [[thread_position_in_grid]]) |
| { |
| - const uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF; |
| uint baseIndex = 0; |
| uint onIndex = 0; |
| uint onOutIndex = 0; |
| @@ -2777,7 +2775,7 @@ kernel void fixIndexBuffer( |
| onOutIndex = prim * 3; |
| break; |
| } |
| - outputPrimitive(indexBufferUint16, indexBufferUint32, outIndexBufferUint16, outIndexBufferUint32, restartIndex, indexCount, baseIndex, onIndex, onOutIndex); |
| + outputPrimitive(indexBufferUint16, indexBufferUint32, outIndexBufferUint16, outIndexBufferUint32, indexCount, baseIndex, onIndex, onOutIndex); |
| } |
| } |
| static inline void generatePrimitive( |
| diff --git a/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_src_autogen.h b/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_src_autogen.h |
| index 3d708205b2f75e6feb4303aebfc080e3425aeae4..076ae9a4d1e281468dfcb35bafc6b6bccfb42a07 100644 |
| --- a/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_src_autogen.h |
| +++ b/src/libANGLE/renderer/metal/shaders/mtl_internal_shaders_src_autogen.h |
| @@ -2550,10 +2550,10 @@ constant bool outIndexBufferIsUint16 = (((fixIndexBufferKey >> 2U) & 0x03U) == 2 |
| constant bool outIndexBufferIsUint32 = (((fixIndexBufferKey >> 2U) & 0x03U) == 3U); |
| constant bool doPrimRestart = (fixIndexBufferKey & 0x00100U); |
| constant uint fixIndexBufferMode = (fixIndexBufferKey >> 4U) & 0x0FU; |
| +constant uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF; |
| static inline uint readIdx( |
| const device ushort *indexBufferUint16, |
| const device uint *indexBufferUint32, |
| - const uint restartIndex, |
| const uint indexCount, |
| uint idx, |
| thread bool &foundRestart, |
| @@ -2589,7 +2589,6 @@ static inline void outputPrimitive( |
| const device uint *indexBufferUint32, |
| device ushort *outIndexBufferUint16, |
| device uint *outIndexBufferUint32, |
| - const uint restartIndex, |
| const uint indexCount, |
| thread uint &baseIndex, |
| uint onIndex, |
| @@ -2603,7 +2602,7 @@ static inline void outputPrimitive( |
| { |
| case 0x00U: |
| { |
| - auto tmpIndex = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2615,8 +2614,8 @@ static inline void outputPrimitive( |
| break; |
| case 0x01U: |
| { |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2644,8 +2643,8 @@ static inline void outputPrimitive( |
| break; |
| case 0x03U: |
| { |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2667,9 +2666,9 @@ static inline void outputPrimitive( |
| break; |
| case 0x04U: |
| { |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2702,9 +2701,9 @@ static inline void outputPrimitive( |
| case 0x05U: |
| { |
| uint isOdd = ((onIndex - baseIndex) & 1); |
| - auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 0 + isOdd, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 1 - isOdd, foundRestart, indexThatRestartedFirst); |
| - auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex0 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 0 + isOdd, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex1 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 1 - isOdd, foundRestart, indexThatRestartedFirst); |
| + auto tmpIndex2 = readIdx(indexBufferUint16, indexBufferUint32, indexCount, onIndex + 2, foundRestart, indexThatRestartedFirst); |
| if(foundRestart) |
| { |
| baseIndex = indexThatRestartedFirst + 1; |
| @@ -2749,7 +2748,6 @@ kernel void fixIndexBuffer( |
| constant uint &primCount [[ buffer(3) ]], |
| uint prim [[thread_position_in_grid]]) |
| { |
| - const uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF; |
| uint baseIndex = 0; |
| uint onIndex = 0; |
| uint onOutIndex = 0; |
| @@ -2778,7 +2776,7 @@ kernel void fixIndexBuffer( |
| onOutIndex = prim * 3; |
| break; |
| } |
| - outputPrimitive(indexBufferUint16, indexBufferUint32, outIndexBufferUint16, outIndexBufferUint32, restartIndex, indexCount, baseIndex, onIndex, onOutIndex); |
| + outputPrimitive(indexBufferUint16, indexBufferUint32, outIndexBufferUint16, outIndexBufferUint32, indexCount, baseIndex, onIndex, onOutIndex); |
| } |
| } |
| static inline void generatePrimitive( |
| diff --git a/src/libANGLE/renderer/metal/shaders/rewrite_indices.metal b/src/libANGLE/renderer/metal/shaders/rewrite_indices.metal |
| index dd0e5dc5924b595ca6b6bab725e59e1f886ae091..5565f3a0d97740ee8a46ab45c14a034a4485b8e0 100644 |
| --- a/src/libANGLE/renderer/metal/shaders/rewrite_indices.metal |
| +++ b/src/libANGLE/renderer/metal/shaders/rewrite_indices.metal |
| @@ -18,12 +18,12 @@ constant bool outIndexBufferIsUint16 = (((fixIndexBufferKey >> MtlFixIndexBuffer |
| constant bool outIndexBufferIsUint32 = (((fixIndexBufferKey >> MtlFixIndexBufferKeyOutShift) & MtlFixIndexBufferKeyTypeMask) == MtlFixIndexBufferKeyUint32); |
| constant bool doPrimRestart = (fixIndexBufferKey & MtlFixIndexBufferKeyPrimRestart); |
| constant uint fixIndexBufferMode = (fixIndexBufferKey >> MtlFixIndexBufferKeyModeShift) & MtlFixIndexBufferKeyModeMask; |
| +constant uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF; |
| |
| |
| static inline uint readIdx( |
| const device ushort *indexBufferUint16, |
| const device uint *indexBufferUint32, |
| - const uint restartIndex, |
| const uint indexCount, |
| uint idx, |
| thread bool &foundRestart, |
| @@ -60,7 +60,6 @@ static inline void outputPrimitive( |
| const device uint *indexBufferUint32, |
| device ushort *outIndexBufferUint16, |
| device uint *outIndexBufferUint32, |
| - const uint restartIndex, |
| const uint indexCount, |
| thread uint &baseIndex, |
| uint onIndex, |
| @@ -70,7 +69,7 @@ static inline void outputPrimitive( |
| if(baseIndex > onIndex) return; // skipped indices while processing |
| bool foundRestart = false; |
| uint indexThatRestartedFirst = 0; |
| -#define READ_IDX(_idx) readIdx(indexBufferUint16, indexBufferUint32, restartIndex, indexCount, _idx, foundRestart, indexThatRestartedFirst) |
| +#define READ_IDX(_idx) readIdx(indexBufferUint16, indexBufferUint32, indexCount, _idx, foundRestart, indexThatRestartedFirst) |
| #define WRITE_IDX(_idx, _val) \ |
| ({ \ |
| if(outIndexBufferIsUint16) \ |
| @@ -244,7 +243,6 @@ kernel void fixIndexBuffer( |
| constant uint &primCount [[ buffer(3) ]], |
| uint prim [[thread_position_in_grid]]) |
| { |
| - const uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF; |
| uint baseIndex = 0; |
| uint onIndex = 0; |
| uint onOutIndex = 0; |
| @@ -273,7 +271,7 @@ kernel void fixIndexBuffer( |
| onOutIndex = prim * 3; |
| break; |
| } |
| - outputPrimitive(indexBufferUint16, indexBufferUint32, outIndexBufferUint16, outIndexBufferUint32, restartIndex, indexCount, baseIndex, onIndex, onOutIndex); |
| + outputPrimitive(indexBufferUint16, indexBufferUint32, outIndexBufferUint16, outIndexBufferUint32, indexCount, baseIndex, onIndex, onOutIndex); |
| } |
| } |
| |
| diff --git a/src/libANGLE/renderer/vulkan/AllocatorHelperPool.cpp b/src/libANGLE/renderer/vulkan/AllocatorHelperPool.cpp |
| index c7ea21b169cd27baaf9bd62cb320a54642a339f2..086756b248cfaf398524cf1d97f96cc813c512ea 100644 |
| --- a/src/libANGLE/renderer/vulkan/AllocatorHelperPool.cpp |
| +++ b/src/libANGLE/renderer/vulkan/AllocatorHelperPool.cpp |
| @@ -49,7 +49,7 @@ bool DedicatedCommandBlockPool::empty() const |
| void DedicatedCommandBlockPool::allocateNewBlock(size_t blockSize) |
| { |
| ASSERT(mAllocator); |
| - mCurrentWritePointer = mAllocator->fastAllocate(blockSize); |
| + mCurrentWritePointer = reinterpret_cast<uint8_t *>(mAllocator->allocate(blockSize)); |
| mCurrentBytesRemaining = blockSize; |
| mCommandBuffer->pushToCommands(mCurrentWritePointer); |
| } |
| diff --git a/src/libANGLE/renderer/vulkan/AllocatorHelperPool.h b/src/libANGLE/renderer/vulkan/AllocatorHelperPool.h |
| index ea37c1e33040e2c4b6f6870c39efa2f4f14d8cd9..166144cdaf22136e46c1c02de2a15029b0d4c778 100644 |
| --- a/src/libANGLE/renderer/vulkan/AllocatorHelperPool.h |
| +++ b/src/libANGLE/renderer/vulkan/AllocatorHelperPool.h |
| @@ -40,10 +40,9 @@ class DedicatedCommandBlockAllocator |
| DedicatedCommandMemoryAllocator *getAllocator() { return &mAllocator; } |
| |
| private: |
| - static constexpr size_t kDefaultPoolAllocatorPageSize = 16 * 1024; |
| // Using a pool allocator per CBH to avoid threading issues that occur w/ shared allocator |
| // between multiple CBHs. |
| - DedicatedCommandMemoryAllocator mAllocator{kDefaultPoolAllocatorPageSize, 1}; |
| + DedicatedCommandMemoryAllocator mAllocator; |
| }; |
| |
| // Used in SecondaryCommandBuffer |
| @@ -61,8 +60,8 @@ class DedicatedCommandBlockPool final |
| using CommandHeaderIDType = uint16_t; |
| // Make sure the size of command header ID type is less than total command header size. |
| static_assert(sizeof(CommandHeaderIDType) < kCommandHeaderSize, "Check size of CommandHeader"); |
| - // Pool Alloc uses 16kB pages w/ 16byte header = 16368bytes. To minimize waste |
| - // using a 16368/12 = 1364. Also better perf than 1024 due to fewer block allocations |
| + // PoolAllocator uses 32768 byte pools. To minimize waste using a 32768/24 = 1365. |
| + // Also better perf than 1024 due to fewer block allocations. |
| static constexpr size_t kBlockSize = 1360; |
| // Make sure block size is 8-byte aligned to avoid ASAN errors. |
| static_assert((kBlockSize % 8) == 0, "Check kBlockSize alignment"); |
| diff --git a/src/libANGLE/renderer/vulkan/CLProgramVk.cpp b/src/libANGLE/renderer/vulkan/CLProgramVk.cpp |
| index ba9c6371d7904fe3fb5c45f0d8e4c23c7e300982..bd8ae62e51ee109a9f01976b983289530be89418 100644 |
| --- a/src/libANGLE/renderer/vulkan/CLProgramVk.cpp |
| +++ b/src/libANGLE/renderer/vulkan/CLProgramVk.cpp |
| @@ -944,6 +944,11 @@ bool CLProgramVk::buildInternal(const cl::DevicePtrs &devices, |
| // add clspv compiler options based on device features |
| processedOptions += ClspvGetCompilerOptions(&device->getImpl<CLDeviceVk>()); |
| |
| + cl_uint addressBits; |
| + ANGLE_CL_IMPL_TRY(device->getInfo(cl::DeviceInfo::AddressBits, sizeof(cl_uint), |
| + &addressBits, nullptr)); |
| + processedOptions += addressBits == 64 ? " -arch=spir64" : " -arch=spir"; |
| + |
| switch (buildType) |
| { |
| case BuildType::BUILD: |
| diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp |
| index 1d35bc668a2d59f1e969d7fb0debd2521cb981e0..400717122aaa2e1d865c9f18c170b9c0090296b9 100644 |
| --- a/src/libANGLE/renderer/vulkan/ContextVk.cpp |
| +++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp |
| @@ -6071,6 +6071,10 @@ angle::Result ContextVk::syncState(const gl::Context *context, |
| break; |
| case gl::state::EXTENDED_DIRTY_BIT_BLEND_ADVANCED_COHERENT: |
| break; |
| + case gl::state::EXTENDED_DIRTY_BIT_VARIABLE_RASTERIZATION_RATE: |
| + // Noop until addition of backend support for |
| + // ANGLE_variable_rasterization_rate_metal extension |
| + break; |
| default: |
| UNREACHABLE(); |
| } |
| diff --git a/src/libANGLE/renderer/vulkan/vk_format_utils.cpp b/src/libANGLE/renderer/vulkan/vk_format_utils.cpp |
| index bf0150c63b7f7d2078baa26f09f17c2e5df0c0f3..17b61a65d5698ae4592469823ac4c216d38b06d3 100644 |
| --- a/src/libANGLE/renderer/vulkan/vk_format_utils.cpp |
| +++ b/src/libANGLE/renderer/vulkan/vk_format_utils.cpp |
| @@ -350,7 +350,7 @@ angle::FormatID ExternalFormatTable::getOrAllocExternalFormatID(uint64_t externa |
| |
| if (mExternalYuvFormats.size() >= kMaxExternalFormatCountSupported) |
| { |
| - ERR() << "ANGLE only suports maximum " << kMaxExternalFormatCountSupported |
| + ERR() << "ANGLE only supports maximum " << kMaxExternalFormatCountSupported |
| << " external renderable formats"; |
| ASSERT(false); |
| return angle::FormatID::NONE; |
| diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp |
| index acf619718b8486c235b1509b914df1156c3c6dcc..24d3065c266d3e415ef57e482970463194ceab82 100644 |
| --- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp |
| +++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp |
| @@ -9105,10 +9105,9 @@ angle::Result ImageHelper::calculateBufferInfo(ContextVk *contextVk, |
| return angle::Result::Continue; |
| } |
| |
| - ANGLE_VK_CHECK_MATH(contextVk, formatInfo.computeRowDepthSkipBytes( |
| - type, glExtents.width, glExtents.height, unpack, is3D, |
| - inputRowPitch, inputDepthPitch, inputSkipBytes)); |
| - |
| + ANGLE_VK_CHECK_MATH( |
| + contextVk, formatInfo.computeRowDepthSkipBytes(type, glExtents, unpack, is3D, inputRowPitch, |
| + inputDepthPitch, inputSkipBytes)); |
| return angle::Result::Continue; |
| } |
| |
| diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp |
| index cae85418ff665badf9a5d797f82852a153c31465..dfcc2727ed169203deeb92bef1641cbd18c19735 100644 |
| --- a/src/libANGLE/validationEGL.cpp |
| +++ b/src/libANGLE/validationEGL.cpp |
| @@ -3600,11 +3600,11 @@ bool ValidateCreatePixmapSurface(const ValidationContext *val, |
| |
| if (!(config->surfaceType & EGL_PIXMAP_BIT)) |
| { |
| - val->setError(EGL_BAD_MATCH, "Congfig does not suport pixmaps."); |
| + val->setError(EGL_BAD_MATCH, "Config does not support pixmaps."); |
| return false; |
| } |
| |
| - ANGLE_EGL_TRY_RETURN(val->eglThread, display->valdiatePixmap(config, pixmap, attributes), |
| + ANGLE_EGL_TRY_RETURN(val->eglThread, display->validatePixmap(config, pixmap, attributes), |
| val->entryPoint, val->labeledObject, false); |
| |
| return true; |
| @@ -7197,7 +7197,7 @@ bool ValidateQuerySurface64KHR(const ValidationContext *val, |
| break; |
| default: |
| { |
| - EGLint querySurfaceValue; |
| + EGLint querySurfaceValue = 0; |
| ANGLE_VALIDATION_TRY( |
| ValidateQuerySurface(val, dpy, surfaceID, attribute, &querySurfaceValue)); |
| } |
| diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h |
| index 66dcc4a020e8ea786a09919f5f686c0ef4606632..69530c6dfdb8195aa32e488ce03e809dfc9d145f 100644 |
| --- a/src/libANGLE/validationES.h |
| +++ b/src/libANGLE/validationES.h |
| @@ -1166,13 +1166,13 @@ ANGLE_INLINE bool ValidateDrawElementsCommon(const Context *context, |
| // If we use an index greater than our maximum supported index range, return an error. |
| // The ES3 spec does not specify behaviour here, it is undefined, but ANGLE should |
| // always return an error if possible here. |
| - if (static_cast<GLint64>(indexRange.end()) >= context->getCaps().maxElementIndex) |
| + if (indexRange.end() >= context->getCaps().maxElementIndex) |
| { |
| ANGLE_VALIDATION_ERROR(GL_INVALID_OPERATION, err::kExceedsMaxElement); |
| return false; |
| } |
| |
| - if (!ValidateDrawAttribs(context, entryPoint, static_cast<GLint64>(indexRange.end()))) |
| + if (!ValidateDrawAttribs(context, entryPoint, indexRange.end())) |
| { |
| return false; |
| } |
| diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp |
| index 5b0ad439b9c9c5ea3a00412aa3baae64adc0dcf8..fabd4e51e20064a15411eae1cfef4f62746f729d 100644 |
| --- a/src/libANGLE/validationES2.cpp |
| +++ b/src/libANGLE/validationES2.cpp |
| @@ -709,6 +709,9 @@ bool ValidCapUncommon(const PrivateState &state, ErrorSet *errors, GLenum cap, b |
| case GL_BLEND_ADVANCED_COHERENT_KHR: |
| return state.getExtensions().blendEquationAdvancedCoherentKHR; |
| |
| + case GL_VARIABLE_RASTERIZATION_RATE_ANGLE: |
| + return state.getExtensions().variableRasterizationRateMetalANGLE; |
| + |
| default: |
| break; |
| } |
| @@ -5968,6 +5971,19 @@ bool ValidateTexImage3DOES(const Context *context, |
| depth, border, format, type, pixels); |
| } |
| |
| +bool ValidateBindMetalRasterizationRateMapANGLE(const Context *context, |
| + angle::EntryPoint entryPoint, |
| + GLuint framebuffer, |
| + GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + if (!context->getExtensions().variableRasterizationRateMetalANGLE) |
| + { |
| + ANGLE_VALIDATION_ERROR(GL_INVALID_OPERATION, kExtensionNotEnabled); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| bool ValidateMultiDrawArraysANGLE(const Context *context, |
| angle::EntryPoint entryPoint, |
| PrimitiveMode mode, |
| diff --git a/src/libANGLE/validationES32.cpp b/src/libANGLE/validationES32.cpp |
| index b54c1be22c192e616ea982a914b7851d75f647bf..56c1ccb081fb15cd647c1949562e4d1edbbb8324 100644 |
| --- a/src/libANGLE/validationES32.cpp |
| +++ b/src/libANGLE/validationES32.cpp |
| @@ -417,12 +417,13 @@ bool ValidateGetPointerv(const Context *context, |
| return false; |
| } |
| break; |
| - |
| + // GL_ANGLE_variable_rasterization_rate_metal |
| + case GL_METAL_RASTERIZATION_RATE_MAP_BINDING_ANGLE: |
| + return context->getExtensions().variableRasterizationRateMetalANGLE; |
| default: |
| ANGLE_VALIDATION_ERROR(GL_INVALID_ENUM, kInvalidPointerQuery); |
| return false; |
| } |
| - |
| return true; |
| } |
| |
| diff --git a/src/libANGLE/validationESEXT.cpp b/src/libANGLE/validationESEXT.cpp |
| index d0c8d2f6a29e4bffd49b8a38eb90ca18e5292be3..0ea9d5bcefeb750fb6c658aa14c628f9827158b3 100644 |
| --- a/src/libANGLE/validationESEXT.cpp |
| +++ b/src/libANGLE/validationESEXT.cpp |
| @@ -3878,6 +3878,29 @@ bool ValidateLogicOpANGLE(const PrivateState &state, |
| return ValidateLogicOpCommon(state, errors, entryPoint, opcodePacked); |
| } |
| |
| +// GL_WEBKIT_explicit_resolve_target |
| +bool ValidateFramebufferResolveRenderbufferWEBKIT(const Context *context, |
| + angle::EntryPoint entryPoint, |
| + GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + RenderbufferID renderbuffer) |
| +{ |
| +#if ANGLE_WEBKIT_EXPLICIT_RESOLVE_TARGET_ENABLED |
| + if (!context->getExtensions().explicitResolveTargetWEBKIT) |
| + { |
| + ANGLE_VALIDATION_ERROR(GL_INVALID_OPERATION, kExtensionNotEnabled); |
| + return false; |
| + } |
| + |
| + return ValidateFramebufferRenderbufferBase(context, entryPoint, target, attachment, |
| + renderbuffertarget, renderbuffer); |
| +#else |
| + UNIMPLEMENTED(); |
| + return false; |
| +#endif |
| +} |
| + |
| bool ValidateFramebufferFoveationConfigQCOM(const Context *context, |
| angle::EntryPoint entryPoint, |
| FramebufferID framebufferPacked, |
| diff --git a/src/libANGLE/validationESEXT_autogen.h b/src/libANGLE/validationESEXT_autogen.h |
| index ae1249104d4183e5d2a353330929237e45c8f79c..208071702dfeb1fde585a1b29590acc43c9d4273 100644 |
| --- a/src/libANGLE/validationESEXT_autogen.h |
| +++ b/src/libANGLE/validationESEXT_autogen.h |
| @@ -839,6 +839,12 @@ bool ValidateGetTranslatedShaderSourceANGLE(const Context *context, |
| const GLsizei *length, |
| const GLchar *source); |
| |
| +// GL_ANGLE_variable_rasterization_rate_metal |
| +bool ValidateBindMetalRasterizationRateMapANGLE(const Context *context, |
| + angle::EntryPoint entryPoint, |
| + GLuint framebuffer, |
| + GLMTLRasterizationRateMapANGLE map); |
| + |
| // GL_ANGLE_vulkan_image |
| bool ValidateAcquireTexturesANGLE(const Context *context, |
| angle::EntryPoint entryPoint, |
| @@ -2740,6 +2746,14 @@ bool ValidateStartTilingQCOM(const Context *context, |
| GLuint width, |
| GLuint height, |
| GLbitfield preserveMask); |
| + |
| +// GL_WEBKIT_explicit_resolve_target |
| +bool ValidateFramebufferResolveRenderbufferWEBKIT(const Context *context, |
| + angle::EntryPoint entryPoint, |
| + GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + RenderbufferID renderbufferPacked); |
| } // namespace gl |
| |
| #endif // LIBANGLE_VALIDATION_ESEXT_AUTOGEN_H_ |
| diff --git a/src/libGLESv2/egl_stubs_getprocaddress_autogen.cpp b/src/libGLESv2/egl_stubs_getprocaddress_autogen.cpp |
| index 4758c7873cb623d6911522c1564ed0511c0f7b7b..cfe3cd51f6946502b93dc1e782bdeaf318459c84 100644 |
| --- a/src/libGLESv2/egl_stubs_getprocaddress_autogen.cpp |
| +++ b/src/libGLESv2/egl_stubs_getprocaddress_autogen.cpp |
| @@ -181,6 +181,7 @@ const ProcEntry g_procTable[] = { |
| {"glBindFramebuffer", P(GL_BindFramebuffer)}, |
| {"glBindFramebufferOES", P(GL_BindFramebufferOES)}, |
| {"glBindImageTexture", P(GL_BindImageTexture)}, |
| + {"glBindMetalRasterizationRateMapANGLE", P(GL_BindMetalRasterizationRateMapANGLE)}, |
| {"glBindProgramPipeline", P(GL_BindProgramPipeline)}, |
| {"glBindProgramPipelineEXT", P(GL_BindProgramPipelineEXT)}, |
| {"glBindRenderbuffer", P(GL_BindRenderbuffer)}, |
| @@ -391,6 +392,7 @@ const ProcEntry g_procTable[] = { |
| {"glFramebufferPixelLocalStorageRestoreANGLE", P(GL_FramebufferPixelLocalStorageRestoreANGLE)}, |
| {"glFramebufferRenderbuffer", P(GL_FramebufferRenderbuffer)}, |
| {"glFramebufferRenderbufferOES", P(GL_FramebufferRenderbufferOES)}, |
| + {"glFramebufferResolveRenderbufferWEBKIT", P(GL_FramebufferResolveRenderbufferWEBKIT)}, |
| {"glFramebufferShadingRateEXT", P(GL_FramebufferShadingRateEXT)}, |
| {"glFramebufferTexture", P(GL_FramebufferTexture)}, |
| {"glFramebufferTexture2D", P(GL_FramebufferTexture2D)}, |
| diff --git a/src/libGLESv2/entry_points_gles_ext_autogen.cpp b/src/libGLESv2/entry_points_gles_ext_autogen.cpp |
| index e9089e5dd496dbf6286bec92e458fc4e440d48a9..252e09eba05f689045b1eb8025fefe14c0d64ebb 100644 |
| --- a/src/libGLESv2/entry_points_gles_ext_autogen.cpp |
| +++ b/src/libGLESv2/entry_points_gles_ext_autogen.cpp |
| @@ -6110,6 +6110,55 @@ void GL_APIENTRY GL_GetTranslatedShaderSourceANGLE(GLuint shader, |
| ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); |
| } |
| |
| +// GL_ANGLE_variable_rasterization_rate_metal |
| +void GL_APIENTRY GL_BindMetalRasterizationRateMapANGLE(GLuint framebuffer, |
| + GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); |
| + Context *context = GetValidGlobalContext(); |
| + ANGLE_UNSAFE_TODO(EVENT(context, GLBindMetalRasterizationRateMapANGLE, |
| + "context = %d, framebuffer = %u, map = 0x%016" PRIxPTR "", CID(context), |
| + framebuffer, (uintptr_t)map)); |
| + |
| + if (ANGLE_LIKELY(context != nullptr)) |
| + { |
| + SCOPED_SHARE_CONTEXT_LOCK(context); |
| + bool isCallValid = context->skipValidation(); |
| + if (!isCallValid) |
| + { |
| + if (ANGLE_LIKELY(context->getExtensions().variableRasterizationRateMetalANGLE)) |
| + { |
| +#if defined(ANGLE_ENABLE_ASSERTS) |
| + const uint32_t errorCount = context->getPushedErrorCount(); |
| +#endif |
| + isCallValid = ValidateBindMetalRasterizationRateMapANGLE( |
| + context, angle::EntryPoint::GLBindMetalRasterizationRateMapANGLE, framebuffer, |
| + map); |
| +#if defined(ANGLE_ENABLE_ASSERTS) |
| + ASSERT(context->getPushedErrorCount() - errorCount == (isCallValid ? 0 : 1)); |
| +#endif |
| + } |
| + else |
| + { |
| + RecordVersionErrorESEXT(context, |
| + angle::EntryPoint::GLBindMetalRasterizationRateMapANGLE); |
| + } |
| + } |
| + if (ANGLE_LIKELY(isCallValid)) |
| + { |
| + context->bindMetalRasterizationRateMap(framebuffer, map); |
| + } |
| + ANGLE_CAPTURE_GL(BindMetalRasterizationRateMapANGLE, isCallValid, context, framebuffer, |
| + map); |
| + } |
| + else |
| + { |
| + GenerateContextLostErrorOnCurrentGlobalContext( |
| + angle::EntryPoint::GLBindMetalRasterizationRateMapANGLE); |
| + } |
| + ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); |
| +} |
| + |
| // GL_ANGLE_vulkan_image |
| void GL_APIENTRY GL_AcquireTexturesANGLE(GLuint numTextures, |
| const GLuint *textures, |
| @@ -20155,4 +20204,60 @@ GL_StartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield p |
| ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); |
| } |
| |
| +// GL_WEBKIT_explicit_resolve_target |
| +void GL_APIENTRY GL_FramebufferResolveRenderbufferWEBKIT(GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + GLuint renderbuffer) |
| +{ |
| + ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); |
| + Context *context = GetValidGlobalContext(); |
| + ANGLE_UNSAFE_TODO(EVENT( |
| + context, GLFramebufferResolveRenderbufferWEBKIT, |
| + "context = %d, target = %s, attachment = %s, renderbuffertarget = %s, renderbuffer = %u", |
| + CID(context), GLenumToString(GLESEnum::AllEnums, target), |
| + GLenumToString(GLESEnum::AllEnums, attachment), |
| + GLenumToString(GLESEnum::AllEnums, renderbuffertarget), renderbuffer)); |
| + |
| + if (ANGLE_LIKELY(context != nullptr)) |
| + { |
| + RenderbufferID renderbufferPacked = PackParam<RenderbufferID>(renderbuffer); |
| + SCOPED_SHARE_CONTEXT_LOCK(context); |
| + bool isCallValid = context->skipValidation(); |
| + if (!isCallValid) |
| + { |
| + if (ANGLE_LIKELY(context->getExtensions().explicitResolveTargetWEBKIT)) |
| + { |
| +#if defined(ANGLE_ENABLE_ASSERTS) |
| + const uint32_t errorCount = context->getPushedErrorCount(); |
| +#endif |
| + isCallValid = ValidateFramebufferResolveRenderbufferWEBKIT( |
| + context, angle::EntryPoint::GLFramebufferResolveRenderbufferWEBKIT, target, |
| + attachment, renderbuffertarget, renderbufferPacked); |
| +#if defined(ANGLE_ENABLE_ASSERTS) |
| + ASSERT(context->getPushedErrorCount() - errorCount == (isCallValid ? 0 : 1)); |
| +#endif |
| + } |
| + else |
| + { |
| + RecordVersionErrorESEXT(context, |
| + angle::EntryPoint::GLFramebufferResolveRenderbufferWEBKIT); |
| + } |
| + } |
| + if (ANGLE_LIKELY(isCallValid)) |
| + { |
| + context->framebufferResolveRenderbufferWEBKIT(target, attachment, renderbuffertarget, |
| + renderbufferPacked); |
| + } |
| + ANGLE_CAPTURE_GL(FramebufferResolveRenderbufferWEBKIT, isCallValid, context, target, |
| + attachment, renderbuffertarget, renderbufferPacked); |
| + } |
| + else |
| + { |
| + GenerateContextLostErrorOnCurrentGlobalContext( |
| + angle::EntryPoint::GLFramebufferResolveRenderbufferWEBKIT); |
| + } |
| + ASSERT(!egl::Display::GetCurrentThreadUnlockedTailCall()->any()); |
| +} |
| + |
| } // extern "C" |
| diff --git a/src/libGLESv2/entry_points_gles_ext_autogen.h b/src/libGLESv2/entry_points_gles_ext_autogen.h |
| index 7c088818930baa0d6a7c8e82414783fd88e43735..62d0cfe3d3062279de5dfe9ace74246c3fa231bb 100644 |
| --- a/src/libGLESv2/entry_points_gles_ext_autogen.h |
| +++ b/src/libGLESv2/entry_points_gles_ext_autogen.h |
| @@ -619,6 +619,10 @@ ANGLE_EXPORT void GL_APIENTRY GL_GetTranslatedShaderSourceANGLE(GLuint shader, |
| GLsizei *length, |
| GLchar *source); |
| |
| +// GL_ANGLE_variable_rasterization_rate_metal |
| +ANGLE_EXPORT void GL_APIENTRY |
| +GL_BindMetalRasterizationRateMapANGLE(GLuint framebuffer, GLMTLRasterizationRateMapANGLE map); |
| + |
| // GL_ANGLE_vulkan_image |
| ANGLE_EXPORT void GL_APIENTRY GL_AcquireTexturesANGLE(GLuint numTextures, |
| const GLuint *textures, |
| @@ -1883,6 +1887,12 @@ ANGLE_EXPORT void GL_APIENTRY GL_TextureFoveationParametersQCOM(GLuint texture, |
| ANGLE_EXPORT void GL_APIENTRY GL_EndTilingQCOM(GLbitfield preserveMask); |
| ANGLE_EXPORT void GL_APIENTRY |
| GL_StartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask); |
| + |
| +// GL_WEBKIT_explicit_resolve_target |
| +ANGLE_EXPORT void GL_APIENTRY GL_FramebufferResolveRenderbufferWEBKIT(GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + GLuint renderbuffer); |
| } // extern "C" |
| |
| #endif // LIBGLESV2_ENTRY_POINTS_GLES_EXT_AUTOGEN_H_ |
| diff --git a/src/libGLESv2/libGLESv2_autogen.cpp b/src/libGLESv2/libGLESv2_autogen.cpp |
| index 24d945ac9e79efd3c4db87d8fe397d4b8b68de40..7343190dce5e4304b16cbf53b36c170b07f63e0f 100644 |
| --- a/src/libGLESv2/libGLESv2_autogen.cpp |
| +++ b/src/libGLESv2/libGLESv2_autogen.cpp |
| @@ -3738,6 +3738,13 @@ void GL_APIENTRY glGetTranslatedShaderSourceANGLE(GLuint shader, |
| return GL_GetTranslatedShaderSourceANGLE(shader, bufSize, length, source); |
| } |
| |
| +// GL_ANGLE_variable_rasterization_rate_metal |
| +void GL_APIENTRY glBindMetalRasterizationRateMapANGLE(GLuint framebuffer, |
| + GLMTLRasterizationRateMapANGLE map) |
| +{ |
| + return GL_BindMetalRasterizationRateMapANGLE(framebuffer, map); |
| +} |
| + |
| // GL_ANGLE_vulkan_image |
| void GL_APIENTRY glAcquireTexturesANGLE(GLuint numTextures, |
| const GLuint *textures, |
| @@ -5957,4 +5964,14 @@ glStartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield pr |
| return GL_StartTilingQCOM(x, y, width, height, preserveMask); |
| } |
| |
| +// GL_WEBKIT_explicit_resolve_target |
| +void GL_APIENTRY glFramebufferResolveRenderbufferWEBKIT(GLenum target, |
| + GLenum attachment, |
| + GLenum renderbuffertarget, |
| + GLuint renderbuffer) |
| +{ |
| + return GL_FramebufferResolveRenderbufferWEBKIT(target, attachment, renderbuffertarget, |
| + renderbuffer); |
| +} |
| + |
| } // extern "C" |
| diff --git a/src/libGLESv2/libGLESv2_autogen.def b/src/libGLESv2/libGLESv2_autogen.def |
| index 82447140b7629fe5316d95430931158c17a56914..767c2e63fd6f021ffb4477d5539f63bfb0c1ea68 100644 |
| --- a/src/libGLESv2/libGLESv2_autogen.def |
| +++ b/src/libGLESv2/libGLESv2_autogen.def |
| @@ -648,6 +648,9 @@ EXPORTS |
| ; GL_ANGLE_translated_shader_source |
| glGetTranslatedShaderSourceANGLE |
| |
| + ; GL_ANGLE_variable_rasterization_rate_metal |
| + glBindMetalRasterizationRateMapANGLE |
| + |
| ; GL_ANGLE_vulkan_image |
| glAcquireTexturesANGLE |
| glReleaseTexturesANGLE |
| @@ -1288,6 +1291,9 @@ EXPORTS |
| glEndTilingQCOM |
| glStartTilingQCOM |
| |
| + ; GL_WEBKIT_explicit_resolve_target |
| + glFramebufferResolveRenderbufferWEBKIT |
| + |
| ; EGL 1.0 |
| EGL_ChooseConfig |
| EGL_CopyBuffers |
| diff --git a/src/libGLESv2/libGLESv2_no_capture_autogen.def b/src/libGLESv2/libGLESv2_no_capture_autogen.def |
| index 159dffad72372e86bccb7ed03cc08a8c82aa6dac..af5bba493520643be4dbe4755635a936a9eeb189 100644 |
| --- a/src/libGLESv2/libGLESv2_no_capture_autogen.def |
| +++ b/src/libGLESv2/libGLESv2_no_capture_autogen.def |
| @@ -648,6 +648,9 @@ EXPORTS |
| ; GL_ANGLE_translated_shader_source |
| glGetTranslatedShaderSourceANGLE |
| |
| + ; GL_ANGLE_variable_rasterization_rate_metal |
| + glBindMetalRasterizationRateMapANGLE |
| + |
| ; GL_ANGLE_vulkan_image |
| glAcquireTexturesANGLE |
| glReleaseTexturesANGLE |
| @@ -1288,6 +1291,9 @@ EXPORTS |
| glEndTilingQCOM |
| glStartTilingQCOM |
| |
| + ; GL_WEBKIT_explicit_resolve_target |
| + glFramebufferResolveRenderbufferWEBKIT |
| + |
| ; EGL 1.0 |
| EGL_ChooseConfig |
| EGL_CopyBuffers |
| diff --git a/src/libGLESv2/libGLESv2_vulkan_secondaries_autogen.def b/src/libGLESv2/libGLESv2_vulkan_secondaries_autogen.def |
| index 032798a1f07297341c09135b1196ad901e097cb6..5adb48659dfc947de51586ed9642d81083a7be76 100644 |
| --- a/src/libGLESv2/libGLESv2_vulkan_secondaries_autogen.def |
| +++ b/src/libGLESv2/libGLESv2_vulkan_secondaries_autogen.def |
| @@ -648,6 +648,9 @@ EXPORTS |
| ; GL_ANGLE_translated_shader_source |
| glGetTranslatedShaderSourceANGLE |
| |
| + ; GL_ANGLE_variable_rasterization_rate_metal |
| + glBindMetalRasterizationRateMapANGLE |
| + |
| ; GL_ANGLE_vulkan_image |
| glAcquireTexturesANGLE |
| glReleaseTexturesANGLE |
| @@ -1288,6 +1291,9 @@ EXPORTS |
| glEndTilingQCOM |
| glStartTilingQCOM |
| |
| + ; GL_WEBKIT_explicit_resolve_target |
| + glFramebufferResolveRenderbufferWEBKIT |
| + |
| ; EGL 1.0 |
| EGL_ChooseConfig |
| EGL_CopyBuffers |
| diff --git a/src/libGLESv2/libGLESv2_with_capture_autogen.def b/src/libGLESv2/libGLESv2_with_capture_autogen.def |
| index c542e9b150f0fa5ab0c150e6b668f2f7dab547df..dbd7368552a3e7c8ec23afd042c0046bbc809f1a 100644 |
| --- a/src/libGLESv2/libGLESv2_with_capture_autogen.def |
| +++ b/src/libGLESv2/libGLESv2_with_capture_autogen.def |
| @@ -648,6 +648,9 @@ EXPORTS |
| ; GL_ANGLE_translated_shader_source |
| glGetTranslatedShaderSourceANGLE |
| |
| + ; GL_ANGLE_variable_rasterization_rate_metal |
| + glBindMetalRasterizationRateMapANGLE |
| + |
| ; GL_ANGLE_vulkan_image |
| glAcquireTexturesANGLE |
| glReleaseTexturesANGLE |
| @@ -1288,6 +1291,9 @@ EXPORTS |
| glEndTilingQCOM |
| glStartTilingQCOM |
| |
| + ; GL_WEBKIT_explicit_resolve_target |
| + glFramebufferResolveRenderbufferWEBKIT |
| + |
| ; EGL 1.0 |
| EGL_ChooseConfig |
| EGL_CopyBuffers |
| diff --git a/src/tests/angle_deqp_tests_main.cpp b/src/tests/angle_deqp_tests_main.cpp |
| index 0943c311aec4ccee5cc4e15b08a4df8366caf2e6..d2b950c572580cbda24ee8223bfe853321846ae0 100644 |
| --- a/src/tests/angle_deqp_tests_main.cpp |
| +++ b/src/tests/angle_deqp_tests_main.cpp |
| @@ -19,7 +19,7 @@ int RunGLCTSTests(int *argc, char **argv); |
| |
| int main(int argc, char **argv) |
| { |
| -#if defined(ANGLE_PLATFORM_MACOS) |
| +#if defined(ANGLE_PLATFORM_MACOS) && defined(ANGLE_OUTSIDE_WEBKIT) |
| // By default, we should hook file API functions on macOS to avoid slow Metal shader caching |
| // file access. |
| angle::InitMetalFileAPIHooking(argc, argv); |
| diff --git a/src/tests/angle_end2end_tests.gni b/src/tests/angle_end2end_tests.gni |
| index f9b5c123dbc65788bc6668921e22ab490a0562d5..a9693931c18965cf6a29e8e21640f5ff020c6a78 100644 |
| --- a/src/tests/angle_end2end_tests.gni |
| +++ b/src/tests/angle_end2end_tests.gni |
| @@ -96,6 +96,7 @@ angle_end2end_tests_sources = [ |
| "gl_tests/GLSLConstantFoldingTest.cpp", |
| "gl_tests/GLSLOutputTest.cpp", |
| "gl_tests/GLSLTest.cpp", |
| + "gl_tests/GLSLUBTest.cpp", |
| "gl_tests/GLSLValidationTest.cpp", |
| "gl_tests/GeometryShaderTest.cpp", |
| "gl_tests/GetImageTest.cpp", |
| diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt |
| index 3d17e1b945f596a8524627487da5c6f1e6f80c7e..1bc12348fce6deb8a73f199a82fce1f5a467c148 100644 |
| --- a/src/tests/angle_end2end_tests_expectations.txt |
| +++ b/src/tests/angle_end2end_tests_expectations.txt |
| @@ -506,7 +506,6 @@ |
| 494392011 MAC METAL : MipmapTestES3.MismatchingLevelFormats/* = SKIP |
| 494341324 MAC OPENGL : MipmapTestES3.MismatchingLevelFormats/* = SKIP |
| 496604559 MAC METAL : RobustResourceInitTestES3.DrawThenInvalidateThenVerifyDepthStencil/* = SKIP |
| -515709506 MAC METAL : DrawBaseVertexBaseInstanceTest_ES3.BaseInstanceSmallDivisorClientMemory/* = SKIP |
| 518849408 MAC OPENGL : GLSLTest.EmulateGLFragColorBroadcastInvariantFragColor/* = SKIP |
| 518849408 MAC OPENGL : GLSLTest.EmulateGLFragColorBroadcastInvariantFragColorUnused/* = SKIP |
| 524008572 MAC METAL : VertexAttributeTestES3.LargeAttribPointerOffsetNoCrash/* = SKIP |
| @@ -556,6 +555,10 @@ |
| 351275980 MAC METAL : GLSLTest_ES3.DynamicIndexingOfSwizzledLValuesShouldWork2/* = SKIP |
| 351275980 IOS METAL : GLSLTest_ES3.DynamicIndexingOfSwizzledLValuesShouldWork2/* = SKIP |
| |
| +// Validation failure. Correctly handled in WebGL. |
| +0 MAC METAL : Texture2DTestES3.TexImageFormatMismatch/ES3_Metal* = SKIP |
| +0 IOS METAL : Texture2DTestES3.TexImageFormatMismatch/ES3_Metal* = SKIP |
| + |
| // D3D |
| 42264944 WIN D3D9 : GLSLValidationTest.HandleExcessiveLoopBug/* = SKIP |
| 42264653 WIN D3D11 : GLSLTestLoops.*ContinueInSwitch/* = SKIP |
| @@ -1367,8 +1370,6 @@ |
| 40096874 IOS METAL : CubeMapTextureTest.SampleCoordinateTransformGrad_ES3/* = SKIP |
| 40096874 IOS METAL : EGLDisplaySelectionTestDeviceId.DeviceId/* = SKIP |
| 40096874 IOS METAL : EGLDisplaySelectionTestDeviceId.DeviceIdConcurrently/* = SKIP |
| -40096874 IOS METAL : ETC1CompressedTextureTest.ETC1CompressedImageDraws/* = SKIP |
| -40096874 IOS METAL : KTXCompressedTextureTest.CompressedTexImageETC1/* = SKIP |
| 40096874 IOS METAL : MaxTextureSizeTest.Render1xTexture/* = SKIP |
| 40096874 IOS METAL : MultisampleTest.AlphaToSampleCoverage/* = SKIP |
| 40096838 IOS METAL : PixelLocalStorageTest.BlendColorMaskAndClear/ES3_Metal_EmulatePixelLocalStorage* = SKIP |
| @@ -1446,30 +1447,15 @@ |
| 40096883 IOS METAL : Texture2DDepthStencilTestES3.TexSampleModes*Swizzled/* = SKIP |
| 375244081 IOS METAL : GLSLTest_ES3.MaxVaryingWithFeedbackAndGLline/* = SKIP |
| 496604559 IOS METAL : RobustResourceInitTestES3.DrawThenInvalidateThenVerifyDepthStencil/* = SKIP |
| -507904704 IOS METAL : CompressedTextureASTCTest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureEACR11STest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureEACR11UTest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureEACRG11STest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureEACRG11UTest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureETC1SubTest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureETC2RGB8A1SRGBTest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureETC2RGB8A1Test.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureETC2RGB8SRGBTest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureETC2RGB8Test.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureETC2RGBA8SRGBTest.Test/* = SKIP |
| -507904704 IOS METAL : CompressedTextureETC2RGBA8Test.Test/* = SKIP |
| -507904704 IOS METAL : ETC1CompressedTextureTest.ETC1CompressedImageNPOT/* = SKIP |
| -507904704 IOS METAL : ETC1CompressedTextureTest.ETC1CompressedSubImage/* = SKIP |
| -507904704 IOS METAL : ETC1CompressedTextureTest.ETC1ShrinkThenGrowMaxLevels/* = SKIP |
| -507904704 IOS METAL : Texture2DTestES3.SampleThenFullUpdateThenSampleAgainCompressed/* = SKIP |
| -507904704 IOS METAL : TextureSizeLimitTest.CompressedASTC/* = SKIP |
| -507904704 IOS METAL : WebGLCompatibilityTest.EnableCompressedTextureExtensionETC1/* = SKIP |
| |
| // Simulator does not support compare functions in the sampler state |
| 365066518 IOS METAL : ShadowSamplerFunctionTexture2DTest.Test/* = SKIP |
| 365066518 IOS METAL : ShadowSamplerFunctionTexture2DArrayTest.Test/* = SKIP |
| 365066518 IOS METAL : ShadowSamplerFunctionTextureCubeTest.Test/* = SKIP |
| |
| +// webkit.org/b/316306 |
| +0 IOSSIMULATOR METAL : WebGL2CompatibilityTest.CompressedTextureASTCEmptyStorageError/* = SKIP |
| + |
| // D3D11 backend does not support LOD options with shadow samplers |
| 365066518 D3D11 : ShadowSamplerFunctionTexture2DTest.Test/*__TextureBias_Mipmapped = SKIP |
| 365066518 D3D11 : ShadowSamplerFunctionTexture2DTest.Test/*__TextureOffsetBias_Mipmapped = SKIP |
| @@ -2901,6 +2887,15 @@ |
| // Unimplemented parts. |
| 515493666 D3D11 : Restart/DrawElementsVariantsTest.Draw/* = SKIP |
| |
| +0 METAL : IncompatibleTextureTest.*/* = SKIP |
| +0 METAL : WebGL2GLSLValidationTest.ManyChainedBinaryExpressions/* = SKIP |
| + |
| +// rdar://129353155 |
| +0 METAL IOSSIMULATOR DEBUGLAYERS : DrawBuffersTestES3.CubeMapTextures/* = SKIP |
| + |
| +// webkit.org/b/317381 |
| +0 METAL : HardenedContextTest.RenderingFeedbackLoopWithStencilOnlyANGLE/* = SKIP |
| + |
| // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| // Slow tests, should appear last in this file |
| // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
| diff --git a/src/tests/angle_end2end_tests_main.cpp b/src/tests/angle_end2end_tests_main.cpp |
| index 4f00793375d478dde14643c118deed5b134289e0..89337e7fc3d995b01252271ba90d81b398f99abd 100644 |
| --- a/src/tests/angle_end2end_tests_main.cpp |
| +++ b/src/tests/angle_end2end_tests_main.cpp |
| @@ -6,9 +6,7 @@ |
| |
| #include "common/unsafe_buffers.h" |
| #include "gtest/gtest.h" |
| -#if defined(ANGLE_HAS_RAPIDJSON) |
| -# include "test_utils/runner/TestSuite.h" |
| -#endif // defined(ANGLE_HAS_RAPIDJSON) |
| +#include "test_utils/runner/TestSuite.h" |
| #include "util/OSWindow.h" |
| |
| void ANGLEProcessTestArgs(int *argc, char *argv[]); |
| @@ -47,9 +45,6 @@ int main(int argc, char **argv) |
| return EXIT_FAILURE; |
| } |
| |
| - // TODO(b/279980674): TestSuite depends on rapidjson which we don't have in aosp builds, |
| - // for now disable both TestSuite and expectations. |
| -#if defined(ANGLE_HAS_RAPIDJSON) |
| ANGLEProcessTestArgs(&argc, argv); |
| |
| auto registerTestsCallback = [] { |
| @@ -80,8 +75,4 @@ int main(int argc, char **argv) |
| } |
| |
| return testSuite.run(); |
| -#else |
| - ::testing::InitGoogleTest(&argc, argv); |
| - return RUN_ALL_TESTS(); |
| -#endif // defined(ANGLE_HAS_RAPIDJSON) |
| } |
| diff --git a/src/tests/angle_unittest_main.cpp b/src/tests/angle_unittest_main.cpp |
| index d2239dc882d94f52e281a8514fad0432ed9ef8fb..ff52612d4b784b02a516c082a710797035be21fa 100644 |
| --- a/src/tests/angle_unittest_main.cpp |
| +++ b/src/tests/angle_unittest_main.cpp |
| @@ -42,7 +42,6 @@ int main(int argc, char **argv) |
| gVerbose = true; |
| } |
| } |
| - |
| angle::TestSuite testSuite(&argc, argv); |
| testing::AddGlobalTestEnvironment(new CompilerTestEnvironment()); |
| return testSuite.run(); |
| diff --git a/src/tests/compiler_tests/MSLOutput_test.cpp b/src/tests/compiler_tests/MSLOutput_test.cpp |
| index 63caf4d128f4f7387b7a35c1de33039fecc149cc..396af8e456068c7721abb7664a170967e97e1a82 100644 |
| --- a/src/tests/compiler_tests/MSLOutput_test.cpp |
| +++ b/src/tests/compiler_tests/MSLOutput_test.cpp |
| @@ -10,6 +10,7 @@ |
| #include <regex> |
| #include "GLSLANG/ShaderLang.h" |
| #include "angle_gl.h" |
| +#include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "tests/test_utils/compiler_test.h" |
| |
| @@ -1085,3 +1086,102 @@ void F(int v) { g = v; } |
| void main() { F(1), F(g); })"; |
| compile(kShader, options); |
| } |
| + |
| +// Tests that uint assignment operators use the expected functions. |
| +TEST_F(MSLOutputTest, UintAssignmentOperators) |
| +{ |
| + const std::string &shaderString = R"(#version 300 es |
| +precision highp float; |
| +in vec4 i; |
| +out vec4 o; |
| +void main() { |
| + ivec4 ii = ivec4(i); |
| + ii += 2; |
| + ii -= 3; |
| + ii *= 4; |
| + ii /= 5; |
| + ii %= 6; |
| + ii &= 7; |
| + ii |= 8; |
| + ii ^= 9; |
| + ii <<= 10; |
| + ii >>= 11; |
| + ii++; |
| + ++ii; |
| + ii--; |
| + --ii; |
| + o = vec4(ii); |
| +})"; |
| + const char expected[] = |
| + R"(void ANGLE__0_main(thread ANGLE_FragmentOut & ANGLE_fragmentOut, thread ANGLE_FragmentIn & ANGLE_fragmentIn) |
| +{ |
| + metal::int4 _uii = ANGLE_ftoi<metal::int4>(ANGLE_fragmentIn._ui); |
| + _uii = ANGLE_addAssignInt(_uii, 2); |
| + _uii = ANGLE_subAssignInt(_uii, 3); |
| + _uii = ANGLE_imul(_uii, 4); |
| + _uii = ANGLE_div(_uii, 5); |
| + _uii = ANGLE_imod(_uii, 6); |
| + _uii &= 7; |
| + _uii |= 8; |
| + _uii ^= 9; |
| + _uii = ANGLE_ilshift(_uii, 10); |
| + _uii = ANGLE_rshift(_uii, 11); |
| + ANGLE_postIncrementInt(_uii); |
| + ANGLE_preIncrementInt(_uii); |
| + ANGLE_postDecrementInt(_uii); |
| + ANGLE_preDecrementInt(_uii); |
| + ANGLE_fragmentOut._uo = metal::float4(_uii); |
| +})"; |
| + compile(shaderString); |
| + EXPECT_THAT(outputCode(SH_MSL_METAL_OUTPUT), testing::HasSubstr(expected)); |
| +} |
| + |
| +// Tests that some uint assignment operators use the swizzle ref helper if the swizzle is in lvalue |
| +// position in the generated code. |
| +TEST_F(MSLOutputTest, UintSwizzleAssignmentOperators) |
| +{ |
| + const std::string &shaderString = R"(#version 300 es |
| +precision highp float; |
| +in vec4 i; |
| +out vec4 o; |
| +void main() { |
| + ivec4 ii = ivec4(i); |
| + ii.x += 2; |
| + ii.y -= 3; |
| + ii.z *= 4; |
| + ii.w /= 5; |
| + ii.x %= 6; |
| + ii.y &= 7; |
| + ii.y |= 8; |
| + ii.z ^= 9; |
| + ii.y <<= 10; |
| + ii.z >>= 11; |
| + ii.x++; |
| + ++ii.y; |
| + ii.x--; |
| + --ii.y; |
| + o = vec4(ii); |
| +})"; |
| + const char expected[] = |
| + R"(void ANGLE__0_main(thread ANGLE_FragmentOut & ANGLE_fragmentOut, thread ANGLE_FragmentIn & ANGLE_fragmentIn) |
| +{ |
| + metal::int4 _uii = ANGLE_ftoi<metal::int4>(ANGLE_fragmentIn._ui); |
| + _uii.x = ANGLE_addInt(_uii.x, 2); |
| + _uii.y = ANGLE_subInt(_uii.y, 3); |
| + _uii.z = ANGLE_imul(_uii.z, 4); |
| + _uii.w = ANGLE_div(_uii.w, 5); |
| + _uii.x = ANGLE_imod(_uii.x, 6); |
| + _uii.y = (_uii.y & 7); |
| + _uii.y = (_uii.y | 8); |
| + _uii.z = (_uii.z ^ 9); |
| + _uii.y = ANGLE_ilshift(_uii.y, 10); |
| + _uii.z = ANGLE_rshift(_uii.z, 11); |
| + ANGLE_postIncrementInt(ANGLE_swizzle_ref(_uii, 0u)); |
| + ANGLE_preIncrementInt(ANGLE_swizzle_ref(_uii, 1u)); |
| + ANGLE_postDecrementInt(ANGLE_swizzle_ref(_uii, 0u)); |
| + ANGLE_preDecrementInt(ANGLE_swizzle_ref(_uii, 1u)); |
| + ANGLE_fragmentOut._uo = metal::float4(_uii); |
| +})"; |
| + compile(shaderString); |
| + EXPECT_THAT(outputCode(SH_MSL_METAL_OUTPUT), testing::HasSubstr(expected)); |
| +} |
| diff --git a/src/tests/deqp_support/angle_deqp_gtest.cpp b/src/tests/deqp_support/angle_deqp_gtest.cpp |
| index f63dbd1e8e19ee2460e8873738c89b4f62579422..b3a9e41ac85b14df08f8a2f0151835408170dbdd 100644 |
| --- a/src/tests/deqp_support/angle_deqp_gtest.cpp |
| +++ b/src/tests/deqp_support/angle_deqp_gtest.cpp |
| @@ -228,7 +228,7 @@ const char *GetDefaultAPIName() |
| defined(ANGLE_PLATFORM_WINDOWS) |
| return "angle-vulkan"; |
| #elif defined(ANGLE_PLATFORM_APPLE) |
| - return "angle-gl"; |
| + return "angle-metal"; |
| #else |
| # error Unknown platform. |
| #endif |
| diff --git a/src/tests/deqp_support/tcuANGLENativeDisplayFactory.cpp b/src/tests/deqp_support/tcuANGLENativeDisplayFactory.cpp |
| index a870b185ce9ec8890ec46f0a61c6f7cbb9a279bb..5db651a0333181c22aa8bb68da9662981e4c7930 100644 |
| --- a/src/tests/deqp_support/tcuANGLENativeDisplayFactory.cpp |
| +++ b/src/tests/deqp_support/tcuANGLENativeDisplayFactory.cpp |
| @@ -503,9 +503,12 @@ eglu::NativeDisplay *ANGLENativeDisplayFactory::createDisplay( |
| DE_UNREF(attribList); |
| if (mPlatformType == EGL_PLATFORM_ANGLE_ANGLE) |
| { |
| + // Support static linking with -DANGLE_EGL_LIBRARY_NAME \"\" |
| + const char *eglLibraryName = |
| + (ANGLE_EGL_LIBRARY_NAME[0] == '\0') ? nullptr : ANGLE_EGL_LIBRARY_FULL_NAME; |
| return new ANGLENativeDisplay(bitCast<EGLNativeDisplayType>(mNativeDisplay), |
| mPlatformAttributes, mPlatformType, |
| - ANGLE_EGL_LIBRARY_FULL_NAME); |
| + eglLibraryName); |
| } |
| #if (DE_OS == DE_OS_ANDROID) |
| else if (mPlatformType == EGL_PLATFORM_ANDROID_KHR) |
| diff --git a/src/tests/egl_tests/EGLContextCompatibilityTest.cpp b/src/tests/egl_tests/EGLContextCompatibilityTest.cpp |
| index 1868f6c946d206a547ce4c90f074c04c36a391ad..0c008b1ddfb7ef17cd009c7566d756da76a369ca 100644 |
| --- a/src/tests/egl_tests/EGLContextCompatibilityTest.cpp |
| +++ b/src/tests/egl_tests/EGLContextCompatibilityTest.cpp |
| @@ -173,8 +173,9 @@ class EGLContextCompatibilityTest : public ANGLETestBase |
| void SetUp() final |
| { |
| ANGLETestBase::ANGLETestSetUp(); |
| +#if !defined(EGL_EGL_PROTOTYPES) || !EGL_EGL_PROTOTYPES |
| ASSERT_TRUE(eglGetPlatformDisplay != nullptr); |
| - |
| +#endif |
| EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, mRenderer, EGL_NONE}; |
| mDisplay = eglGetPlatformDisplay(GetEglPlatform(), |
| reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs); |
| @@ -493,11 +494,13 @@ void RegisterContextCompatibilityTests() |
| |
| LoadEntryPointsWithUtilLoader(kDefaultGLESDriver); |
| |
| +#if !defined(EGL_EGL_PROTOTYPES) || !EGL_EGL_PROTOTYPES |
| if (eglGetPlatformDisplay == nullptr) |
| { |
| std::cerr << "EGLContextCompatibilityTest: missing eglGetPlatformDisplay\n"; |
| return; |
| } |
| +#endif |
| |
| for (EGLint renderer : renderers) |
| { |
| diff --git a/src/tests/egl_tests/EGLDisplaySelectionTest.cpp b/src/tests/egl_tests/EGLDisplaySelectionTest.cpp |
| index f68de4db0037643faf0fd8fcf06709c663463948..886a1d73ab521aa189d95d8cb651f9c63451b939 100644 |
| --- a/src/tests/egl_tests/EGLDisplaySelectionTest.cpp |
| +++ b/src/tests/egl_tests/EGLDisplaySelectionTest.cpp |
| @@ -69,7 +69,7 @@ class EGLDisplaySelectionTestNoFixture : public EGLDisplaySelectionTest |
| { |
| mOSWindow = OSWindow::New(); |
| mOSWindow->initialize("EGLDisplaySelectionTestMultiDisplay", kWindowWidth, kWindowHeight); |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| } |
| |
| void initializeContextForDisplay(EGLDisplay display, EGLContext *context) |
| diff --git a/src/tests/egl_tests/EGLDisplayTest.cpp b/src/tests/egl_tests/EGLDisplayTest.cpp |
| index b51b5f07cba261dddef39cc80115986108722bab..817668c08b7a018ad2525aa9999914c42836ddc7 100644 |
| --- a/src/tests/egl_tests/EGLDisplayTest.cpp |
| +++ b/src/tests/egl_tests/EGLDisplayTest.cpp |
| @@ -182,7 +182,9 @@ TEST_P(EGLDisplayTest, GetPlatformDisplayEXT) |
| // eglGetPlatformDisplayEXT() requires EGL_EXT_platform_base. |
| ANGLE_SKIP_TEST_IF(!IsEGLClientExtensionEnabled("EGL_EXT_platform_base")); |
| |
| +#if !defined(EGL_EGLEXT_PROTOTYPES) || !EGL_EGLEXT_PROTOTYPES |
| ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr); |
| +#endif |
| |
| EGLint dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE}; |
| EGLDisplay display = eglGetPlatformDisplayEXT( |
| diff --git a/src/tests/egl_tests/EGLRobustnessTest.cpp b/src/tests/egl_tests/EGLRobustnessTest.cpp |
| index cc31654e5b252b4f908ec1e77285daf7af1e5391..81043a037d827b2cdf411c068872dc4a2938b22e 100644 |
| --- a/src/tests/egl_tests/EGLRobustnessTest.cpp |
| +++ b/src/tests/egl_tests/EGLRobustnessTest.cpp |
| @@ -32,7 +32,7 @@ class EGLRobustnessTest : public ANGLETest<> |
| { |
| mOSWindow = OSWindow::New(); |
| mOSWindow->initialize("EGLRobustnessTest", 500, 500); |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| const auto &platform = GetParam().eglParameters; |
| |
| diff --git a/src/tests/egl_tests/EGLSurfaceTest.cpp b/src/tests/egl_tests/EGLSurfaceTest.cpp |
| index c6b61daa103ee863bfa1a796175849ada3fbccb9..b95c4814d871734f0c5a149f470ae932c0a6cf07 100644 |
| --- a/src/tests/egl_tests/EGLSurfaceTest.cpp |
| +++ b/src/tests/egl_tests/EGLSurfaceTest.cpp |
| @@ -757,7 +757,7 @@ TEST_P(EGLSurfaceTest, SurfaceUseAfterFreeBug) |
| // Test that the window can be reset repeatedly before surface creation. |
| TEST_P(EGLSurfaceTest, ResetNativeWindow) |
| { |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| @@ -3262,7 +3262,7 @@ TEST_P(EGLSurfaceTest, DISABLED_RandomClearTearing) |
| // the app get over the problem. |
| TEST_P(EGLSurfaceTest, DestroyAndRecreateWhileCurrent) |
| { |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| @@ -3820,7 +3820,7 @@ TEST_P(EGLSurfaceTest, ResizeAfterSwap) |
| constexpr std::array<int, kSizeCount> kHeights{499, 200}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -3865,7 +3865,7 @@ TEST_P(EGLSurfaceTest, ResizeAfterSwapSkipSizeQuery) |
| constexpr std::array<int, kSizeCount> kHeights{499, 200}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -3900,7 +3900,7 @@ TEST_P(EGLSurfaceTest, ResizeBeforeDraw) |
| constexpr std::array<int, kSizeCount> kHeights{64, 499, 200}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -3953,7 +3953,7 @@ TEST_P(EGLSurfaceTest, ResizeBeforeDrawPostSizeQuery) |
| constexpr std::array<int, kSizeCount> kHeights{64, 499, 200}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -4012,7 +4012,7 @@ TEST_P(EGLSurfaceTest, ResizeAfterDraw) |
| constexpr std::array<int, kSizeCount> kHeights{64, 499, 200}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -4070,7 +4070,7 @@ TEST_P(EGLSurfaceTest, ResizeLargeWindow) |
| constexpr std::array<int, kSizeCount> kHeights{999, 1079}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -4171,7 +4171,7 @@ TEST_P(EGLSurfaceTest, ResizeBeforeMakeCurrent) |
| constexpr std::array<int, kSizeCount> kHeights{64, 499}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -4239,7 +4239,7 @@ TEST_P(EGLSurfaceTest, ResizeBeforeMakeCurrentPostSizeQuery) |
| constexpr std::array<int, kSizeCount> kHeights{64, 499}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -4306,7 +4306,7 @@ TEST_P(EGLSurfaceTest, ResizeAndReadPixelsRobustANGLE) |
| constexpr std::array<int, kSizeCount> kHeights{499, 200}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| initializeSurfaceWithDefaultConfig(true); |
| @@ -4357,7 +4357,7 @@ TEST_P(EGLSurfaceTest, ResizeAndBlitFramebufferANGLE) |
| constexpr std::array<int, kSizeCount> kHeights{499, 200}; |
| |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| @@ -4433,7 +4433,7 @@ class EGLWindowSurfaceColorspaceTestES3 : public EGLSurfaceTest |
| // Test interaction between GL_EXT_sRGB_write_control and default framebuffer |
| TEST_P(EGLWindowSurfaceColorspaceTestES3, ToggleSrgbWriteControl) |
| { |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| @@ -4504,7 +4504,7 @@ TEST_P(EGLWindowSurfaceColorspaceTestES3, ToggleSrgbWriteControl) |
| // wouldn't refresh the framebuffer |
| TEST_P(EGLWindowSurfaceColorspaceTestES3, ToggleSrgbWriteControlWithinRenderPass) |
| { |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| @@ -4580,7 +4580,7 @@ TEST_P(EGLWindowSurfaceColorspaceTestES3, ToggleSrgbWriteControlWithinRenderPass |
| TEST_P(EGLSurfaceTest, PreserveThenClearToBlack) |
| { |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| @@ -4626,7 +4626,7 @@ TEST_P(EGLSurfaceTest, PreserveThenClearToBlack) |
| TEST_P(EGLSurfaceTest, PreserveThenBlend) |
| { |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| @@ -4672,7 +4672,7 @@ TEST_P(EGLSurfaceTest, PreserveThenBlend) |
| TEST_P(EGLSurfaceTest, ClearThenPreserve) |
| { |
| // Necessary for some platforms (NVIDIA on Linux) if there is no per-frame window size query. |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| initializeDisplay(); |
| |
| diff --git a/src/tests/egl_tests/EGLSurfaceTestMac.mm b/src/tests/egl_tests/EGLSurfaceTestMac.mm |
| index 813888146a7ddd670d5a28ee8fcae277dc462099..1862aef3a703b25c5d975602401ba11d5d45f078 100644 |
| --- a/src/tests/egl_tests/EGLSurfaceTestMac.mm |
| +++ b/src/tests/egl_tests/EGLSurfaceTestMac.mm |
| @@ -32,7 +32,7 @@ class EGLSurfaceTestMac : public ANGLETest<> |
| { |
| mOSWindow = OSWindow::New(); |
| mOSWindow->initialize("EGLSurfaceTestMac", kWindowWidth, kWindowHeight); |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| // Get display. |
| EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), |
| diff --git a/src/tests/gl_tests/ContextLostTest.cpp b/src/tests/gl_tests/ContextLostTest.cpp |
| index 1192e7e7828b69347983ead73f848240f4f73c64..3daa4a2cf708810462b04281822da20f42189a16 100644 |
| --- a/src/tests/gl_tests/ContextLostTest.cpp |
| +++ b/src/tests/gl_tests/ContextLostTest.cpp |
| @@ -226,7 +226,9 @@ ANGLE_INSTANTIATE_TEST(ContextLostTest, |
| WithRobustness(ES2_D3D11()), |
| WithRobustness(ES3_D3D11()), |
| WithRobustness(ES2_VULKAN()), |
| - WithRobustness(ES3_VULKAN())); |
| + WithRobustness(ES3_VULKAN()), |
| + WithRobustness(ES2_METAL()), |
| + WithRobustness(ES3_METAL())); |
| |
| ANGLE_INSTANTIATE_TEST(ContextLostSkipValidationTest, |
| WithRobustness(ES2_NULL()), |
| @@ -234,7 +236,9 @@ ANGLE_INSTANTIATE_TEST(ContextLostSkipValidationTest, |
| WithRobustness(ES2_D3D11()), |
| WithRobustness(ES3_D3D11()), |
| WithRobustness(ES2_VULKAN()), |
| - WithRobustness(ES3_VULKAN())); |
| + WithRobustness(ES3_VULKAN()), |
| + WithRobustness(ES2_METAL()), |
| + WithRobustness(ES3_METAL())); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContextLostTestES32); |
| ANGLE_INSTANTIATE_TEST(ContextLostTestES32, WithRobustness(ES32_VULKAN())); |
| diff --git a/src/tests/gl_tests/CopyCompressedTextureTest.cpp b/src/tests/gl_tests/CopyCompressedTextureTest.cpp |
| index 6ddadba63706defe665858101598abf43d7bf3aa..29c31ecfb445af09eb5c5be7c7e9b5819be3cc2f 100644 |
| --- a/src/tests/gl_tests/CopyCompressedTextureTest.cpp |
| +++ b/src/tests/gl_tests/CopyCompressedTextureTest.cpp |
| @@ -67,12 +67,13 @@ class CopyCompressedTextureTest : public ANGLETest<> |
| return false; |
| } |
| |
| +#if !defined(GL_GLEXT_PROTOTYPES) || !GL_GLEXT_PROTOTYPES |
| EXPECT_NE(nullptr, glCompressedCopyTextureCHROMIUM); |
| if (glCompressedCopyTextureCHROMIUM == nullptr) |
| { |
| return false; |
| } |
| - |
| +#endif |
| return true; |
| } |
| |
| diff --git a/src/tests/gl_tests/CopyTexImageTest.cpp b/src/tests/gl_tests/CopyTexImageTest.cpp |
| index eb78cd36ff3e786edb059c5bb095eda7383e3f1c..1677cef086d74d02e79d731d6412625394d415fa 100644 |
| --- a/src/tests/gl_tests/CopyTexImageTest.cpp |
| +++ b/src/tests/gl_tests/CopyTexImageTest.cpp |
| @@ -1455,6 +1455,41 @@ TEST_P(CopyTexImageTestES3, CopyTexSubImageToNonZeroBase) |
| kTexSize, 1.0); |
| } |
| |
| +// Test that copying into a image after unrelated image has been defined with another format works. |
| +TEST_P(CopyTexImageTestES3, CopyTexSubImageAfterIncompatibleDefinition) |
| +{ |
| + constexpr GLsizei kTexSize = 4; |
| + std::vector<GLColor> green(kTexSize * kTexSize, GLColor::green); |
| + |
| + GLTexture srcColor; |
| + glBindTexture(GL_TEXTURE_2D, srcColor); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + green.data()); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, srcColor, 0); |
| + ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + |
| + std::vector<GLColor> red(kTexSize * kTexSize, GLColor::red); |
| + GLTexture dstColor; |
| + glBindTexture(GL_TEXTURE_2D, dstColor); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + red.data()); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + glGenerateMipmap(GL_TEXTURE_2D); // Sync state. |
| + glTexImage2D(GL_TEXTURE_2D, 7, GL_DEPTH_COMPONENT32F, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); // Trigger the bug. |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kTexSize, kTexSize); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + constexpr std::array<GLubyte, 4> kExpected = {0, 255, 0, 255}; |
| + verifyResults(dstColor, kExpected.data(), kTexSize, 0, 0, kTexSize, kTexSize, 1.0); |
| +} |
| + |
| // Initialize the 3D texture we will copy the subImage data into |
| void CopyTexImageTestES3::initialize3DTexture(GLTexture &texture, |
| const GLsizei imageWidth, |
| diff --git a/src/tests/gl_tests/CubeMapTextureTest.cpp b/src/tests/gl_tests/CubeMapTextureTest.cpp |
| index 1bba50cd42e5bc0e4e581956fd2e180593176758..a76b5e8912668d48a825eed39edd9c89419fe05e 100644 |
| --- a/src/tests/gl_tests/CubeMapTextureTest.cpp |
| +++ b/src/tests/gl_tests/CubeMapTextureTest.cpp |
| @@ -8,7 +8,6 @@ |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/angle_test_configs.h" |
| #include "test_utils/gl_raii.h" |
| -#include "util/gles_loader_autogen.h" |
| |
| using namespace angle; |
| |
| diff --git a/src/tests/gl_tests/DrawBaseVertexBaseInstanceTest.cpp b/src/tests/gl_tests/DrawBaseVertexBaseInstanceTest.cpp |
| index 78127dd8beb1e8917b88b9d23bd843f6012cab39..e706c61d0261e6c6b30cc3f1e8d7c04bf743685d 100644 |
| --- a/src/tests/gl_tests/DrawBaseVertexBaseInstanceTest.cpp |
| +++ b/src/tests/gl_tests/DrawBaseVertexBaseInstanceTest.cpp |
| @@ -7,6 +7,10 @@ |
| // DrawBaseVertexBaseInstanceTest: Tests of GL_ANGLE_base_vertex_base_instance |
| // DrawBaseInstanceTest: Tests of GL_EXT_base_instance |
| |
| +#ifdef UNSAFE_BUFFERS_BUILD |
| +# pragma allow_unsafe_buffers |
| +#endif |
| + |
| #include "gpu_info_util/SystemInfo.h" |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| diff --git a/src/tests/gl_tests/DrawBuffersTest.cpp b/src/tests/gl_tests/DrawBuffersTest.cpp |
| index cbcb297f41fac30a0d72e98035a6d347d6c4225e..5920f83fc812faa361841ef009e5182442918d50 100644 |
| --- a/src/tests/gl_tests/DrawBuffersTest.cpp |
| +++ b/src/tests/gl_tests/DrawBuffersTest.cpp |
| @@ -11,6 +11,10 @@ |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| |
| +#include "common/gl_enum_utils.h" |
| + |
| +#include <limits> |
| + |
| using namespace angle; |
| |
| class DrawBuffersTest : public ANGLETest<> |
| @@ -59,7 +63,7 @@ class DrawBuffersTest : public ANGLETest<> |
| } |
| |
| // This test seems to fail on an nVidia machine when the window is hidden |
| - setWindowVisible(getOSWindow(), true); |
| + setWindowVisible(getOSWindow(), shouldShowWindow()); |
| |
| glGenFramebuffers(1, &mFBO); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO); |
| @@ -1777,8 +1781,1063 @@ TEST_P(ColorMaskForDrawBuffersTest, StateChangeAffectsBlendState) |
| EXPECT_GL_NO_ERROR(); |
| } |
| |
| +// Test parameters: <platform, color format, depth/stencil format (0 if none), |
| +// useTexture, sample count (0 = single-sampled)>. |
| +using DrawBuffersAnyFormatVariationsTestParams = |
| + std::tuple<angle::PlatformParameters, GLenum, GLenum, bool, GLint>; |
| + |
| +std::string DrawBuffersAnyFormatVariationsTestPrint( |
| + const ::testing::TestParamInfo<DrawBuffersAnyFormatVariationsTestParams> ¶msInfo) |
| +{ |
| + const DrawBuffersAnyFormatVariationsTestParams ¶ms = paramsInfo.param; |
| + std::ostringstream out; |
| + out << std::get<0>(params) << "__" |
| + << gl::GLenumToString(gl::GLESEnum::AllEnums, std::get<1>(params)) << "_" |
| + << (std::get<2>(params) == 0 |
| + ? "NoDepthStencil" |
| + : gl::GLenumToString(gl::GLESEnum::AllEnums, std::get<2>(params))) |
| + << "_" << (std::get<3>(params) ? "Texture" : "Renderbuffer"); |
| + if (std::get<4>(params) > 0) |
| + { |
| + out << "_MSAA" << std::get<4>(params); |
| + } |
| + return out.str(); |
| +} |
| + |
| +constexpr GLenum kDrawBuffersAnyFormatColorFormats[] = { |
| + // Normalized / float-castable |
| + GL_R8, |
| + GL_RG8, |
| + GL_RGB8, |
| + GL_RGB565, |
| + GL_RGB5_A1, |
| + GL_RGBA4, |
| + GL_RGB10_A2, |
| + GL_RGBA8, |
| + GL_SRGB8_ALPHA8, |
| + // Signed / unsigned integer |
| + GL_R8I, |
| + GL_R8UI, |
| + GL_R16I, |
| + GL_R16UI, |
| + GL_R32I, |
| + GL_R32UI, |
| + GL_RG8I, |
| + GL_RG8UI, |
| + GL_RG16I, |
| + GL_RG16UI, |
| + GL_RG32I, |
| + GL_RG32UI, |
| + GL_RGBA8I, |
| + GL_RGBA8UI, |
| + GL_RGBA16I, |
| + GL_RGBA16UI, |
| + GL_RGBA32I, |
| + GL_RGBA32UI, |
| + GL_RGB10_A2UI, |
| + // Float, require EXT_color_buffer_half_float / EXT_color_buffer_float. |
| + GL_R16F, |
| + GL_RG16F, |
| + GL_RGBA16F, |
| + GL_RGB16F, // Renderable only via EXT_color_buffer_half_float; |
| + GL_R32F, |
| + GL_RG32F, |
| + GL_RGBA32F, |
| + GL_R11F_G11F_B10F, |
| + // Shared exponent, requires GL_QCOM_render_shared_exponent to render. |
| + GL_RGB9_E5, |
| + // Unsigned normalized 16-bit, requires GL_EXT_texture_norm16 to render. |
| + GL_R16_EXT, |
| + GL_RG16_EXT, |
| + GL_RGBA16_EXT, |
| + // Signed normalized 8-bit, requires GL_EXT_render_snorm to render. |
| + GL_R8_SNORM, |
| + GL_RG8_SNORM, |
| + GL_RGBA8_SNORM, |
| + // Signed normalized 16-bit, requires GL_EXT_render_snorm + GL_EXT_texture_norm16 to render. |
| + GL_R16_SNORM_EXT, |
| + GL_RG16_SNORM_EXT, |
| + GL_RGBA16_SNORM_EXT, |
| + // Requires GL_EXT_texture_format_BGRA8888. |
| + GL_BGRA8_EXT, |
| + // Requires GL_ANGLE_rgbx_internal_format. |
| + GL_RGBX8_ANGLE, |
| +}; |
| + |
| +constexpr GLenum kDrawBuffersAnyFormatDepthStencilFormats[] = { |
| + 0, // No depth/stencil attachment |
| + GL_DEPTH_COMPONENT16, |
| + GL_DEPTH_COMPONENT24, |
| + GL_DEPTH_COMPONENT32F, |
| + GL_STENCIL_INDEX8, |
| + GL_DEPTH24_STENCIL8, |
| + GL_DEPTH32F_STENCIL8, |
| +}; |
| + |
| +constexpr GLenum kDrawBuffersAnyFormatMSAAColorFormats[] = { |
| + GL_R8, |
| + GL_RG8, |
| + GL_RGB8, |
| + GL_RGB565, |
| + GL_RGB5_A1, |
| + GL_RGBA4, |
| + GL_RGB10_A2, |
| + GL_RGBA8, |
| + GL_SRGB8_ALPHA8, |
| + // Half/float color. |
| + GL_R16F, |
| + GL_RG16F, |
| + GL_RGBA16F, |
| + // RGB half-float is renderable only via EXT_color_buffer_half_float. |
| + GL_RGB16F, |
| + GL_R32F, |
| + GL_RG32F, |
| + GL_RGBA32F, |
| + GL_R11F_G11F_B10F, |
| + // Shared exponent. |
| + GL_RGB9_E5, |
| + // Unsigned normalized 16-bit. |
| + GL_R16_EXT, |
| + GL_RG16_EXT, |
| + GL_RGBA16_EXT, |
| + // Signed normalized 8-bit. |
| + GL_R8_SNORM, |
| + GL_RG8_SNORM, |
| + GL_RGBA8_SNORM, |
| + // Signed normalized 16-bit. |
| + GL_R16_SNORM_EXT, |
| + GL_RG16_SNORM_EXT, |
| + GL_RGBA16_SNORM_EXT, |
| + // BGRA8, requires GL_EXT_texture_format_BGRA8888. |
| + GL_BGRA8_EXT, |
| + // RGBX8, requires GL_ANGLE_rgbx_internal_format. |
| + GL_RGBX8_ANGLE, |
| +}; |
| + |
| +#if ANGLE_PLATFORM_IOS_FAMILY |
| +constexpr GLint kDrawBuffersAnyFormatMaxTestedSampleCount = 4; |
| +#else |
| +constexpr GLint kDrawBuffersAnyFormatMaxTestedSampleCount = 8; |
| +#endif |
| + |
| +struct DrawBuffersAnyFormatExpectation |
| +{ |
| + const char *deviceNameSubstring; |
| + GLenum colorFormat; |
| + // First draw-buffer count at which the FBO becomes FRAMEBUFFER_UNSUPPORTED. |
| + // Single-sampled (samples == 0) and MSAA paths are tracked separately because |
| + // MSAA samples multiply the per-pixel byte budget. The MSAA value applies to |
| + // every MSAA sample count tested by this suite. |
| + // 0 -- FBO is expected FRAMEBUFFER_UNSUPPORTED at every count |
| + // 9 -- FBO is expected FRAMEBUFFER_COMPLETE at every count |
| + GLint firstFailingDrawBufferCountAliased; |
| + GLint firstFailingDrawBufferCountMSAA; |
| +}; |
| + |
| +// Per-known device results for framebuffer-completeness for the |
| +// (color format, sample count) keys listed. |
| +// If the device does not appear in the table at all, it is unknown |
| +// device. Any framebuffer status at any buffer count is tolerated. |
| +// For known devices: |
| +// For this (color format, sampleCount), the FBO is expected to |
| +// become FRAMEBUFFER_UNSUPPORTED at firstFailingDrawBufferCount |
| +// and remain unsupported for larger counts. |
| +constexpr DrawBuffersAnyFormatExpectation kDrawBuffersAnyFormatExpectedFramebufferIncomplete[] = { |
| +#if ANGLE_PLATFORM_MACOS |
| + // Force expectations by having one result: all framebuffers are complete. |
| + {"", GL_RGBA32F, 9, 9}, |
| +#elif ANGLE_PLATFORM_IOS_FAMILY_SIMULATOR |
| + // Simulator uses a 32-byte color tile budget but its emulated |
| + // pixelBytes don't match a real Apple GPU. Many "small" formats |
| + // come out oversized. |
| + {"Apple iOS simulator GPU", GL_R11F_G11F_B10F, 5, 5}, |
| + {"Apple iOS simulator GPU", GL_RG32F, 5, 0}, |
| + {"Apple iOS simulator GPU", GL_RG32I, 5, 0}, |
| + {"Apple iOS simulator GPU", GL_RG32UI, 5, 0}, |
| + {"Apple iOS simulator GPU", GL_RGB10_A2, 5, 5}, |
| + {"Apple iOS simulator GPU", GL_RGB10_A2UI, 9, 0}, |
| + {"Apple iOS simulator GPU", GL_RGB565, 9, 5}, |
| + {"Apple iOS simulator GPU", GL_RGB5_A1, 9, 5}, |
| + {"Apple iOS simulator GPU", GL_RGB8, 9, 5}, |
| + {"Apple iOS simulator GPU", GL_RGB16F, 5, 5}, |
| + {"Apple iOS simulator GPU", GL_RGBA16F, 5, 5}, |
| + {"Apple iOS simulator GPU", GL_RGBA16I, 5, 0}, |
| + {"Apple iOS simulator GPU", GL_RGBA16UI, 5, 0}, |
| + {"Apple iOS simulator GPU", GL_RGBA32F, 3, 0}, |
| + {"Apple iOS simulator GPU", GL_RGBA32I, 3, 0}, |
| + {"Apple iOS simulator GPU", GL_RGBA32UI, 3, 0}, |
| + {"Apple iOS simulator GPU", GL_RGBA4, 9, 5}, |
| + {"Apple iOS simulator GPU", GL_RGBA8, 9, 5}, |
| + {"Apple iOS simulator GPU", GL_RGBA8_SNORM, 9, 5}, |
| + {"Apple iOS simulator GPU", GL_RGBA16_EXT, 5, 5}, |
| + {"Apple iOS simulator GPU", GL_RGBA16_SNORM_EXT, 5, 5}, |
| + {"Apple iOS simulator GPU", GL_SRGB8_ALPHA8, 9, 5}, |
| + {"Apple iOS simulator GPU", GL_BGRA8_EXT, 9, 5}, |
| +#elif ANGLE_PLATFORM_IOS_FAMILY |
| + // Apple A12*, Apple5, 64 bytes of implicit image block size. |
| + {"Apple A12", GL_RGBA32F, 5, 5}, |
| + {"Apple A12", GL_RGBA32I, 5, 0}, |
| + {"Apple A12", GL_RGBA32UI, 5, 0}, |
| + |
| + // Apple A13*, Apple6, 64 bytes of implicit image block size. |
| + {"Apple A13", GL_RGBA32F, 5, 5}, |
| + {"Apple A13", GL_RGBA32I, 5, 0}, |
| + {"Apple A13", GL_RGBA32UI, 5, 0}, |
| + |
| + // Force expect success, Apple7+, 128 bytes of implicit image block size. |
| + {"Apple A14", GL_RGBA32F, 9, 9}, |
| + {"Apple A15", GL_RGBA32F, 9, 9}, |
| + {"Apple A16", GL_RGBA32F, 9, 9}, |
| + {"Apple A17", GL_RGBA32F, 9, 9}, |
| + {"Apple A18", GL_RGBA32F, 9, 9}, |
| + {"Apple A19", GL_RGBA32F, 9, 9}, |
| + {"Apple M", GL_RGBA32F, 9, 9}, |
| +#endif |
| +}; |
| + |
| +class DrawBuffersAnyFormatTestES3 : public ANGLETest<DrawBuffersAnyFormatVariationsTestParams> |
| +{ |
| + protected: |
| + DrawBuffersAnyFormatTestES3() |
| + { |
| + setWindowWidth(128); |
| + setWindowHeight(128); |
| + setConfigRedBits(8); |
| + setConfigGreenBits(8); |
| + setConfigBlueBits(8); |
| + setConfigAlphaBits(8); |
| + setConfigDepthBits(24); |
| + setConfigStencilBits(8); |
| + } |
| + |
| + GLenum colorFormat() const { return std::get<1>(GetParam()); } |
| + GLenum depthStencilFormat() const { return std::get<2>(GetParam()); } |
| + bool useTexture() const { return std::get<3>(GetParam()); } |
| + GLint samples() const { return std::get<4>(GetParam()); } |
| + |
| + bool isSignedInt() const; |
| + bool isUnsignedInt() const; |
| + bool isFloatColorFormat() const; |
| + bool isSnorm8ColorFormat() const; |
| + bool isSnorm16ColorFormat() const; |
| + |
| + static GLenum DepthStencilAttachmentFor(GLenum format); |
| + static int NumColorChannels(GLenum internalformat); |
| + |
| + void setUpFramebufferAttachments(GLFramebuffer &fb, GLint numAttachments); |
| + |
| + void clearColorAttachment(GLint i); |
| + testing::AssertionResult verifyColorAttachment(GLint i); |
| + |
| + void clearAll(GLint numAttachments); |
| + |
| + // Verifies each color attachment was cleared to its per-attachment value. |
| + testing::AssertionResult verifyAttachments(GLint numAttachments); |
| + |
| + bool deviceSupportsParameters() const; |
| + |
| + testing::AssertionResult verifyKnownDeviceExpectedFramebufferStatus(GLenum status, |
| + GLint numAttachments) const; |
| +}; |
| + |
| +bool DrawBuffersAnyFormatTestES3::isSignedInt() const |
| +{ |
| + switch (colorFormat()) |
| + { |
| + case GL_R8I: |
| + case GL_R16I: |
| + case GL_R32I: |
| + case GL_RG8I: |
| + case GL_RG16I: |
| + case GL_RG32I: |
| + case GL_RGBA8I: |
| + case GL_RGBA16I: |
| + case GL_RGBA32I: |
| + return true; |
| + default: |
| + return false; |
| + } |
| +} |
| + |
| +bool DrawBuffersAnyFormatTestES3::isUnsignedInt() const |
| +{ |
| + switch (colorFormat()) |
| + { |
| + case GL_R8UI: |
| + case GL_R16UI: |
| + case GL_R32UI: |
| + case GL_RG8UI: |
| + case GL_RG16UI: |
| + case GL_RG32UI: |
| + case GL_RGBA8UI: |
| + case GL_RGBA16UI: |
| + case GL_RGBA32UI: |
| + case GL_RGB10_A2UI: |
| + return true; |
| + default: |
| + return false; |
| + } |
| +} |
| + |
| +GLenum DrawBuffersAnyFormatTestES3::DepthStencilAttachmentFor(GLenum format) |
| +{ |
| + switch (format) |
| + { |
| + case GL_DEPTH_COMPONENT16: |
| + case GL_DEPTH_COMPONENT24: |
| + case GL_DEPTH_COMPONENT32F: |
| + return GL_DEPTH_ATTACHMENT; |
| + case GL_STENCIL_INDEX8: |
| + return GL_STENCIL_ATTACHMENT; |
| + case GL_DEPTH24_STENCIL8: |
| + case GL_DEPTH32F_STENCIL8: |
| + return GL_DEPTH_STENCIL_ATTACHMENT; |
| + default: |
| + return 0; |
| + } |
| +} |
| + |
| +bool DrawBuffersAnyFormatTestES3::isFloatColorFormat() const |
| +{ |
| + switch (colorFormat()) |
| + { |
| + case GL_R16F: |
| + case GL_RG16F: |
| + case GL_RGBA16F: |
| + case GL_RGB16F: |
| + case GL_R32F: |
| + case GL_RG32F: |
| + case GL_RGBA32F: |
| + case GL_R11F_G11F_B10F: |
| + case GL_RGB9_E5: |
| + return true; |
| + default: |
| + return false; |
| + } |
| +} |
| + |
| +bool DrawBuffersAnyFormatTestES3::isSnorm8ColorFormat() const |
| +{ |
| + switch (colorFormat()) |
| + { |
| + case GL_R8_SNORM: |
| + case GL_RG8_SNORM: |
| + case GL_RGBA8_SNORM: |
| + return true; |
| + default: |
| + return false; |
| + } |
| +} |
| + |
| +bool DrawBuffersAnyFormatTestES3::isSnorm16ColorFormat() const |
| +{ |
| + switch (colorFormat()) |
| + { |
| + case GL_R16_SNORM_EXT: |
| + case GL_RG16_SNORM_EXT: |
| + case GL_RGBA16_SNORM_EXT: |
| + return true; |
| + default: |
| + return false; |
| + } |
| +} |
| + |
| +int DrawBuffersAnyFormatTestES3::NumColorChannels(GLenum internalformat) |
| +{ |
| + switch (internalformat) |
| + { |
| + case GL_R8: |
| + case GL_R8I: |
| + case GL_R8UI: |
| + case GL_R16I: |
| + case GL_R16UI: |
| + case GL_R32I: |
| + case GL_R32UI: |
| + case GL_R16F: |
| + case GL_R32F: |
| + case GL_R16_EXT: |
| + case GL_R8_SNORM: |
| + case GL_R16_SNORM_EXT: |
| + return 1; |
| + case GL_RG8: |
| + case GL_RG8I: |
| + case GL_RG8UI: |
| + case GL_RG16I: |
| + case GL_RG16UI: |
| + case GL_RG32I: |
| + case GL_RG32UI: |
| + case GL_RG16F: |
| + case GL_RG32F: |
| + case GL_RG16_EXT: |
| + case GL_RG8_SNORM: |
| + case GL_RG16_SNORM_EXT: |
| + return 2; |
| + case GL_RGB8: |
| + case GL_RGB565: |
| + case GL_RGB16F: |
| + case GL_R11F_G11F_B10F: |
| + case GL_RGB9_E5: |
| + case GL_RGBX8_ANGLE: |
| + return 3; |
| + default: |
| + return 4; |
| + } |
| +} |
| + |
| +void DrawBuffersAnyFormatTestES3::setUpFramebufferAttachments(GLFramebuffer &fb, |
| + GLint numAttachments) |
| +{ |
| + constexpr GLsizei kSize = 16; |
| + const GLenum cFormat = colorFormat(); |
| + const GLenum dsFormat = depthStencilFormat(); |
| + const GLenum dsAttach = DepthStencilAttachmentFor(dsFormat); |
| + const GLint msaa = samples(); |
| + |
| + glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| + |
| + if (useTexture()) |
| + { |
| + // Multisampled textures require ES 3.1 or an extension. The MSAA |
| + // suite uses renderbuffers only; this branch is for samples == 0. |
| + ASSERT_EQ(msaa, 0); |
| + std::vector<GLTexture> colorTexs(numAttachments); |
| + for (GLint i = 0; i < numAttachments; ++i) |
| + { |
| + glBindTexture(GL_TEXTURE_2D, colorTexs[i]); |
| + glTexStorage2D(GL_TEXTURE_2D, 1, cFormat, kSize, kSize); |
| + ASSERT_GL_NO_ERROR() << i; |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, |
| + colorTexs[i], 0); |
| + ASSERT_GL_NO_ERROR() << i; |
| + } |
| + GLTexture dsTex; |
| + if (dsAttach != 0) |
| + { |
| + glBindTexture(GL_TEXTURE_2D, dsTex); |
| + glTexStorage2D(GL_TEXTURE_2D, 1, dsFormat, kSize, kSize); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, dsAttach, GL_TEXTURE_2D, dsTex, 0); |
| + } |
| + glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| + } |
| + else |
| + { |
| + std::vector<GLRenderbuffer> colorRbs(numAttachments); |
| + for (GLint i = 0; i < numAttachments; ++i) |
| + { |
| + glBindRenderbuffer(GL_RENDERBUFFER, colorRbs[i]); |
| + if (msaa > 0) |
| + { |
| + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, cFormat, kSize, kSize); |
| + } |
| + else |
| + { |
| + glRenderbufferStorage(GL_RENDERBUFFER, cFormat, kSize, kSize); |
| + } |
| + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, |
| + colorRbs[i]); |
| + } |
| + GLRenderbuffer dsRb; |
| + if (dsAttach != 0) |
| + { |
| + glBindRenderbuffer(GL_RENDERBUFFER, dsRb); |
| + if (msaa > 0) |
| + { |
| + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, dsFormat, kSize, kSize); |
| + } |
| + else |
| + { |
| + glRenderbufferStorage(GL_RENDERBUFFER, dsFormat, kSize, kSize); |
| + } |
| + glFramebufferRenderbuffer(GL_FRAMEBUFFER, dsAttach, GL_RENDERBUFFER, dsRb); |
| + } |
| + glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| + } |
| +} |
| + |
| +void DrawBuffersAnyFormatTestES3::clearColorAttachment(GLint i) |
| +{ |
| + // Per-attachment R/G/B is the bit decomposition of (i+1); A is always |
| + // "max". Using only 0 / max (=255 / 1.0 / 1) values means the cleared |
| + // values round-trip through any normalized format. |
| + const bool R = ((i + 1) & 1) != 0; |
| + const bool G = ((i + 1) & 2) != 0; |
| + const bool B = ((i + 1) & 4) != 0; |
| + if (isUnsignedInt()) |
| + { |
| + const GLuint v[4] = {R ? 1u : 0u, G ? 1u : 0u, B ? 1u : 0u, 1u}; |
| + glClearBufferuiv(GL_COLOR, i, v); |
| + } |
| + else if (isSignedInt()) |
| + { |
| + const GLint v[4] = {R ? 1 : 0, G ? 1 : 0, B ? 1 : 0, 1}; |
| + glClearBufferiv(GL_COLOR, i, v); |
| + } |
| + else |
| + { |
| + const GLfloat v[4] = {R ? 1.0f : 0.0f, G ? 1.0f : 0.0f, B ? 1.0f : 0.0f, 1.0f}; |
| + glClearBufferfv(GL_COLOR, i, v); |
| + } |
| +} |
| + |
| +testing::AssertionResult DrawBuffersAnyFormatTestES3::verifyColorAttachment(GLint i) |
| +{ |
| + GLFramebuffer resolveFb; |
| + GLRenderbuffer resolveRb; |
| + GLint sourceFb = 0; |
| + |
| + if (samples() > 0) |
| + { |
| + constexpr GLsizei kSize = 16; |
| + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &sourceFb); |
| + |
| + glBindRenderbuffer(GL_RENDERBUFFER, resolveRb); |
| + glRenderbufferStorage(GL_RENDERBUFFER, colorFormat(), kSize, kSize); |
| + |
| + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFb); |
| + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, |
| + resolveRb); |
| + |
| + glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFb); |
| + glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| + glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, sourceFb); |
| + const GLenum blitErr = glGetError(); |
| + if (blitErr != GL_NO_ERROR) |
| + { |
| + glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFb); |
| + return testing::AssertionFailure() |
| + << "MSAA blit-resolve attachment " << i << ": " |
| + << gl::GLenumToString(gl::GLESEnum::AllEnums, blitErr); |
| + } |
| + |
| + glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFb); |
| + glReadBuffer(GL_COLOR_ATTACHMENT0); |
| + } |
| + else |
| + { |
| + glReadBuffer(GL_COLOR_ATTACHMENT0 + i); |
| + } |
| + |
| + const int numC = NumColorChannels(colorFormat()); |
| + |
| + // Mask the expected components by the format's channel count. Channels |
| + // not present in the format read back as 0 (RGB) or "1" (alpha) per the |
| + // ES 3.0 spec. |
| + const bool R = numC >= 1 && ((i + 1) & 1) != 0; |
| + const bool G = numC >= 2 && ((i + 1) & 2) != 0; |
| + const bool B = numC >= 3 && ((i + 1) & 4) != 0; |
| + |
| + testing::AssertionResult result = testing::AssertionSuccess(); |
| + |
| + if (isUnsignedInt()) |
| + { |
| + GLuint pixel[4] = {0u, 0u, 0u, 0u}; |
| + const GLuint expected[4] = {R ? 1u : 0u, G ? 1u : 0u, B ? 1u : 0u, 1u}; |
| + glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_UNSIGNED_INT, pixel); |
| + if (memcmp(pixel, expected, sizeof(pixel)) != 0) |
| + { |
| + result = testing::AssertionFailure() |
| + << "color attachment " << i << ": got (" << pixel[0] << ", " << pixel[1] |
| + << ", " << pixel[2] << ", " << pixel[3] << "), expected (" << expected[0] |
| + << ", " << expected[1] << ", " << expected[2] << ", " << expected[3] << ")"; |
| + } |
| + } |
| + else if (isSignedInt()) |
| + { |
| + GLint pixel[4] = {0, 0, 0, 0}; |
| + const GLint expected[4] = {R ? 1 : 0, G ? 1 : 0, B ? 1 : 0, 1}; |
| + glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_INT, pixel); |
| + if (memcmp(pixel, expected, sizeof(pixel)) != 0) |
| + { |
| + result = testing::AssertionFailure() |
| + << "color attachment " << i << ": got (" << pixel[0] << ", " << pixel[1] |
| + << ", " << pixel[2] << ", " << pixel[3] << "), expected (" << expected[0] |
| + << ", " << expected[1] << ", " << expected[2] << ", " << expected[3] << ")"; |
| + } |
| + } |
| + else if (isSnorm8ColorFormat()) |
| + { |
| + // GL_EXT_render_snorm adds GL_RGBA + GL_BYTE to ReadPixels. SNORM |
| + // 1.0 maps to 127. |
| + GLbyte pixel[4] = {0, 0, 0, 0}; |
| + const GLbyte expected[4] = {static_cast<GLbyte>(R ? 127 : 0), |
| + static_cast<GLbyte>(G ? 127 : 0), |
| + static_cast<GLbyte>(B ? 127 : 0), 127}; |
| + glReadPixels(0, 0, 1, 1, GL_RGBA, GL_BYTE, pixel); |
| + if (std::memcmp(pixel, expected, sizeof(pixel)) != 0) |
| + { |
| + result = testing::AssertionFailure() |
| + << "color attachment " << i << ": got (" << +pixel[0] << ", " << +pixel[1] |
| + << ", " << +pixel[2] << ", " << +pixel[3] << "), expected (" << +expected[0] |
| + << ", " << +expected[1] << ", " << +expected[2] << ", " << +expected[3] << ")"; |
| + } |
| + } |
| + else if (isSnorm16ColorFormat()) |
| + { |
| + // GL_EXT_render_snorm adds GL_RGBA + GL_SHORT to ReadPixels. SNORM |
| + // 1.0 maps to 32767. |
| + GLshort pixel[4] = {0, 0, 0, 0}; |
| + const GLshort expected[4] = {static_cast<GLshort>(R ? 32767 : 0), |
| + static_cast<GLshort>(G ? 32767 : 0), |
| + static_cast<GLshort>(B ? 32767 : 0), 32767}; |
| + glReadPixels(0, 0, 1, 1, GL_RGBA, GL_SHORT, pixel); |
| + if (std::memcmp(pixel, expected, sizeof(pixel)) != 0) |
| + { |
| + result = testing::AssertionFailure() |
| + << "color attachment " << i << ": got (" << pixel[0] << ", " << pixel[1] |
| + << ", " << pixel[2] << ", " << pixel[3] << "), expected (" << expected[0] |
| + << ", " << expected[1] << ", " << expected[2] << ", " << expected[3] << ")"; |
| + } |
| + } |
| + else if (isFloatColorFormat()) |
| + { |
| + const GLColor32F expected(R ? 1.0f : 0.0f, G ? 1.0f : 0.0f, B ? 1.0f : 0.0f, 1.0f); |
| + const GLColor32F actual = angle::ReadColor32F(0, 0); |
| + if (actual != expected) |
| + { |
| + result = testing::AssertionFailure() |
| + << "color attachment " << i << ": got " << actual << ", expected " << expected; |
| + } |
| + } |
| + else |
| + { |
| + const GLColor expected(static_cast<GLubyte>(R ? 255 : 0), static_cast<GLubyte>(G ? 255 : 0), |
| + static_cast<GLubyte>(B ? 255 : 0), 255); |
| + const GLColor actual = angle::ReadColor(0, 0); |
| + if (actual != expected) |
| + { |
| + result = testing::AssertionFailure() |
| + << "color attachment " << i << ": got " << actual << ", expected " << expected; |
| + } |
| + } |
| + |
| + if (samples() > 0) |
| + { |
| + glBindFramebuffer(GL_READ_FRAMEBUFFER, sourceFb); |
| + } |
| + return result; |
| +} |
| + |
| +void DrawBuffersAnyFormatTestES3::clearAll(GLint numAttachments) |
| +{ |
| + const GLenum dsAttach = DepthStencilAttachmentFor(depthStencilFormat()); |
| + |
| + for (GLint i = 0; i < numAttachments; ++i) |
| + { |
| + clearColorAttachment(i); |
| + } |
| + |
| + GLbitfield clearMask = 0; |
| + if (dsAttach == GL_DEPTH_ATTACHMENT || dsAttach == GL_DEPTH_STENCIL_ATTACHMENT) |
| + { |
| + glClearDepthf(1.0f); |
| + clearMask |= GL_DEPTH_BUFFER_BIT; |
| + } |
| + if (dsAttach == GL_STENCIL_ATTACHMENT || dsAttach == GL_DEPTH_STENCIL_ATTACHMENT) |
| + { |
| + glClearStencil(0x55); |
| + clearMask |= GL_STENCIL_BUFFER_BIT; |
| + } |
| + if (clearMask != 0) |
| + { |
| + glClear(clearMask); |
| + } |
| +} |
| + |
| +testing::AssertionResult DrawBuffersAnyFormatTestES3::verifyAttachments(GLint numAttachments) |
| +{ |
| + for (GLint i = 0; i < numAttachments; ++i) |
| + { |
| + testing::AssertionResult r = verifyColorAttachment(i); |
| + if (!r) |
| + { |
| + return r; |
| + } |
| + } |
| + return testing::AssertionSuccess(); |
| +} |
| + |
| +bool DrawBuffersAnyFormatTestES3::deviceSupportsParameters() const |
| +{ |
| + switch (colorFormat()) |
| + { |
| + case GL_R16F: |
| + case GL_RG16F: |
| + case GL_RGBA16F: |
| + if (!EnsureGLExtensionEnabled("GL_EXT_color_buffer_half_float") && |
| + !EnsureGLExtensionEnabled("GL_EXT_color_buffer_float")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_RGB16F: |
| + if (!EnsureGLExtensionEnabled("GL_EXT_color_buffer_half_float")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_R32F: |
| + case GL_RG32F: |
| + case GL_RGBA32F: |
| + case GL_R11F_G11F_B10F: |
| + if (!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_RGB9_E5: |
| + if (!EnsureGLExtensionEnabled("GL_QCOM_render_shared_exponent")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_R16_EXT: |
| + case GL_RG16_EXT: |
| + case GL_RGBA16_EXT: |
| + if (!EnsureGLExtensionEnabled("GL_EXT_texture_norm16")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_R8_SNORM: |
| + case GL_RG8_SNORM: |
| + case GL_RGBA8_SNORM: |
| + if (!EnsureGLExtensionEnabled("GL_EXT_render_snorm")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_R16_SNORM_EXT: |
| + case GL_RG16_SNORM_EXT: |
| + case GL_RGBA16_SNORM_EXT: |
| + if (!EnsureGLExtensionEnabled("GL_EXT_render_snorm") || |
| + !EnsureGLExtensionEnabled("GL_EXT_texture_norm16")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_BGRA8_EXT: |
| + if (!EnsureGLExtensionEnabled("GL_EXT_texture_format_BGRA8888")) |
| + { |
| + return false; |
| + } |
| + break; |
| + case GL_RGBX8_ANGLE: |
| + if (!EnsureGLExtensionEnabled("GL_ANGLE_rgbx_internal_format")) |
| + { |
| + return false; |
| + } |
| + break; |
| + default: |
| + break; |
| + } |
| + |
| + // Stencil-only attachments as textures require GL_OES_texture_stencil8. |
| + // Renderbuffer GL_STENCIL_INDEX8 is required by ES 3.0 with no extension. |
| + if (useTexture() && depthStencilFormat() == GL_STENCIL_INDEX8) |
| + { |
| + if (!EnsureGLExtensionEnabled("GL_OES_texture_stencil8")) |
| + { |
| + return false; |
| + } |
| + } |
| + |
| + if (samples() > 0) |
| + { |
| + if (isSignedInt() || isUnsignedInt()) |
| + { |
| + UNREACHABLE(); |
| + return false; |
| + } |
| + GLint maxSamplesForColor = 0; |
| + glGetInternalformativ(GL_RENDERBUFFER, colorFormat(), GL_SAMPLES, 1, &maxSamplesForColor); |
| + if (samples() > maxSamplesForColor) |
| + { |
| + return false; |
| + } |
| + if (depthStencilFormat() != 0) |
| + { |
| + GLint maxSamplesForDS = 0; |
| + glGetInternalformativ(GL_RENDERBUFFER, depthStencilFormat(), GL_SAMPLES, 1, |
| + &maxSamplesForDS); |
| + if (samples() > maxSamplesForDS) |
| + { |
| + return false; |
| + } |
| + } |
| + } |
| + |
| + return true; |
| +} |
| + |
| +testing::AssertionResult DrawBuffersAnyFormatTestES3::verifyKnownDeviceExpectedFramebufferStatus( |
| + GLenum status, |
| + GLint numAttachments) const |
| +{ |
| + // Known Devices have entry in the table. |
| + // For given (format, samples, numAttachments, status), verify status: |
| + // * A matching entry covers the (format, samples, numAttachments) -> |
| + // Expect status incomplete. |
| + // * status Complete -> success (expectations default to success). |
| + // * status Incomplete -> failure (missing expectation). |
| + |
| + const std::string deviceName(reinterpret_cast<const char *>(glGetString(GL_RENDERER))); |
| + bool hasExpectation = false; |
| + // If we have expectation, the default is that all framebuffers resolve to working. |
| + GLint expectedFirstFailingBufferCount = std::numeric_limits<GLint>::max(); |
| + for (const DrawBuffersAnyFormatExpectation &e : |
| + kDrawBuffersAnyFormatExpectedFramebufferIncomplete) |
| + { |
| + if (deviceName.find(e.deviceNameSubstring) == std::string::npos) |
| + { |
| + continue; |
| + } |
| + // NOTE: If device has any entry in the table, we expect the table fully |
| + // define the status behavior. |
| + hasExpectation = true; |
| + if (e.colorFormat != colorFormat()) |
| + { |
| + continue; |
| + } |
| + expectedFirstFailingBufferCount = (samples() == 0) ? e.firstFailingDrawBufferCountAliased |
| + : e.firstFailingDrawBufferCountMSAA; |
| + } |
| + if (hasExpectation) |
| + { |
| + GLenum expectedStatus = static_cast<GLenum>(numAttachments < expectedFirstFailingBufferCount |
| + ? GL_FRAMEBUFFER_COMPLETE |
| + : GL_FRAMEBUFFER_UNSUPPORTED); |
| + if (status == expectedStatus) |
| + { |
| + return testing::AssertionSuccess(); |
| + } |
| + return testing::AssertionFailure() |
| + << "device: " << deviceName << " n=" << numAttachments << " samples=" << samples() |
| + << " format=" << gl::GLenumToString(gl::GLESEnum::AllEnums, colorFormat()) |
| + << " expected status: " << gl::GLenumToString(gl::GLESEnum::AllEnums, expectedStatus) |
| + << " got status: " << gl::GLenumToString(gl::GLESEnum::AllEnums, status); |
| + } |
| + // Device not in the table: any status is tolerated. Toggle ((false)) -> |
| + // ((true)) to log a candidate row to add to the expectations table. |
| + if (status != GL_FRAMEBUFFER_COMPLETE && ((false))) |
| + { |
| + printf("DrawBuffersAnyFormat incomplete: {\"%s\", %s, /* %s n=%d */},\n", |
| + deviceName.c_str(), gl::GLenumToString(gl::GLESEnum::AllEnums, colorFormat()), |
| + samples() == 0 ? "Aliased" : "MSAA", numAttachments); |
| + } |
| + return testing::AssertionSuccess(); |
| +} |
| + |
| +// Fill FBO with maximum amount of attachments for a specific format. |
| +// Test clear codepath with the FBO. |
| +TEST_P(DrawBuffersAnyFormatTestES3, ClearIterativeAttachmentCount) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!deviceSupportsParameters()); |
| + |
| + GLint maxDrawBuffers = 0; |
| + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| + ASSERT_GE(maxDrawBuffers, 4); |
| + |
| + for (GLint n = maxDrawBuffers; n >= 1; --n) |
| + { |
| + SCOPED_TRACE(testing::Message() << "numAttachments=" << n); |
| + |
| + GLFramebuffer fb; |
| + setUpFramebufferAttachments(fb, n); |
| + glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
| + EXPECT_TRUE(verifyKnownDeviceExpectedFramebufferStatus(status, n)); |
| + if (status != GL_FRAMEBUFFER_COMPLETE) |
| + { |
| + continue; |
| + } |
| + |
| + std::vector<GLenum> drawBuffers(n); |
| + for (GLint i = 0; i < n; ++i) |
| + { |
| + drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| + } |
| + glDrawBuffers(n, drawBuffers.data()); |
| + |
| + clearAll(n); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_TRUE(verifyAttachments(n)); |
| + break; |
| + } |
| +} |
| + |
| +// Fill FBO with maximum amount of attachments for a specific format. |
| +// Test clear-after-draw codepath with the FBO. |
| +TEST_P(DrawBuffersAnyFormatTestES3, DrawThenClearIterativeAttachmentCount) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!deviceSupportsParameters()); |
| + |
| + GLint maxDrawBuffers = 0; |
| + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| + ASSERT_GE(maxDrawBuffers, 4); |
| + |
| + for (GLint n = maxDrawBuffers; n >= 1; --n) |
| + { |
| + SCOPED_TRACE(testing::Message() << "numAttachments=" << n); |
| + |
| + GLFramebuffer fb; |
| + setUpFramebufferAttachments(fb, n); |
| + glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
| + EXPECT_TRUE(verifyKnownDeviceExpectedFramebufferStatus(status, n)); |
| + if (status != GL_FRAMEBUFFER_COMPLETE) |
| + { |
| + continue; |
| + } |
| + |
| + std::vector<GLenum> drawBuffers(n); |
| + for (GLint i = 0; i < n; ++i) |
| + { |
| + drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; |
| + } |
| + glDrawBuffers(n, drawBuffers.data()); |
| + |
| + const GLenum dsAttach = DepthStencilAttachmentFor(depthStencilFormat()); |
| + const bool hasDepth = |
| + dsAttach == GL_DEPTH_ATTACHMENT || dsAttach == GL_DEPTH_STENCIL_ATTACHMENT; |
| + const bool hasStencil = |
| + dsAttach == GL_STENCIL_ATTACHMENT || dsAttach == GL_DEPTH_STENCIL_ATTACHMENT; |
| + if (hasDepth) |
| + { |
| + glEnable(GL_DEPTH_TEST); |
| + glDepthFunc(GL_ALWAYS); |
| + } |
| + else |
| + { |
| + glDisable(GL_DEPTH_TEST); |
| + } |
| + if (hasStencil) |
| + { |
| + glEnable(GL_STENCIL_TEST); |
| + glStencilFunc(GL_ALWAYS, 0x3C, 0xFF); |
| + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); |
| + glStencilMask(0xFF); |
| + } |
| + else |
| + { |
| + glDisable(GL_STENCIL_TEST); |
| + } |
| + |
| + const char *outType = isUnsignedInt() ? "uvec4" : (isSignedInt() ? "ivec4" : "vec4"); |
| + const char *outValue = |
| + isUnsignedInt() ? "uvec4(0u, 0u, 1u, 1u)" |
| + : (isSignedInt() ? "ivec4(0, 0, 1, 1)" : "vec4(0.0, 0.0, 1.0, 1.0)"); |
| + |
| + std::stringstream fs; |
| + fs << "#version 300 es\nprecision highp float;\n"; |
| + for (GLint i = 0; i < n; ++i) |
| + { |
| + fs << "layout(location = " << i << ") out " << outType << " value" << i << ";\n"; |
| + } |
| + fs << "void main(){\n"; |
| + for (GLint i = 0; i < n; ++i) |
| + { |
| + fs << "value" << i << " = " << outValue << ";\n"; |
| + } |
| + fs << "}\n"; |
| + |
| + ANGLE_GL_PROGRAM(drawMRT, essl3_shaders::vs::Simple(), fs.str().c_str()); |
| + drawQuad(drawMRT, essl3_shaders::PositionAttrib(), 0.0f); |
| + |
| + clearAll(n); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_TRUE(verifyAttachments(n)); |
| + break; |
| + } |
| +} |
| + |
| +// Setup a big framebuffer and if it returns incomplete, expect clear to |
| +// fail too. |
| +TEST_P(DrawBuffersAnyFormatTestES3, IncompleteClearIsInvalidFramebufferOperation) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!deviceSupportsParameters()); |
| + |
| + GLint maxDrawBuffers = 0; |
| + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); |
| + ASSERT_GE(maxDrawBuffers, 4); |
| + |
| + for (GLint n = 1; n <= maxDrawBuffers; ++n) |
| + { |
| + SCOPED_TRACE(testing::Message() << "numAttachments=" << n); |
| + |
| + GLFramebuffer fb; |
| + setUpFramebufferAttachments(fb, n); |
| + glBindFramebuffer(GL_FRAMEBUFFER, fb); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
| + EXPECT_TRUE(verifyKnownDeviceExpectedFramebufferStatus(status, n)); |
| + if (status == GL_FRAMEBUFFER_COMPLETE) |
| + { |
| + continue; |
| + } |
| + |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION); |
| + glClear(GL_STENCIL_BUFFER_BIT); |
| + EXPECT_GL_ERROR(GL_INVALID_FRAMEBUFFER_OPERATION); |
| + } |
| +} |
| + |
| +// Sanity test: detects implementations that advertise a per-format max |
| +// sample count exceeding what the MSAA instantiation of |
| +// DrawBuffersAnyFormatTestES3 actually exercises. If this fires, raise |
| +// kDrawBuffersAnyFormatMaxTestedSampleCount and add the new value to the |
| +// MSAA instantiation's sample-count list. |
| +TEST_P(DrawBuffersTestES3, DrawBuffersAnyFormatMSAASampleLimitIsEnough) |
| +{ |
| + EnsureGLExtensionEnabled("GL_EXT_color_buffer_half_float"); |
| + EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"); |
| + EnsureGLExtensionEnabled("GL_QCOM_render_shared_exponent"); |
| + EnsureGLExtensionEnabled("GL_EXT_texture_norm16"); |
| + EnsureGLExtensionEnabled("GL_EXT_render_snorm"); |
| + EnsureGLExtensionEnabled("GL_EXT_texture_format_BGRA8888"); |
| + EnsureGLExtensionEnabled("GL_ANGLE_rgbx_internal_format"); |
| + |
| + auto checkFormat = [&](GLenum fmt) { |
| + GLint numCounts = 0; |
| + glGetInternalformativ(GL_RENDERBUFFER, fmt, GL_NUM_SAMPLE_COUNTS, 1, &numCounts); |
| + if (glGetError() != GL_NO_ERROR) |
| + { |
| + return; |
| + } |
| + if (numCounts == 0) |
| + { |
| + return; |
| + } |
| + GLint maxSamples = 0; |
| + glGetInternalformativ(GL_RENDERBUFFER, fmt, GL_SAMPLES, 1, &maxSamples); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_LE(maxSamples, kDrawBuffersAnyFormatMaxTestedSampleCount) |
| + << "format: " << gl::GLenumToString(gl::GLESEnum::AllEnums, fmt); |
| + }; |
| + |
| + for (GLenum fmt : kDrawBuffersAnyFormatMSAAColorFormats) |
| + { |
| + checkFormat(fmt); |
| + } |
| + for (GLenum fmt : kDrawBuffersAnyFormatDepthStencilFormats) |
| + { |
| + if (fmt == 0) |
| + { |
| + continue; // sentinel for "no depth/stencil attachment" |
| + } |
| + checkFormat(fmt); |
| + } |
| +} |
| + |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(DrawBuffersTest, |
| ES2_METAL().enable(Feature::LimitMaxDrawBuffersForTesting), |
| + ES3_METAL().enable(Feature::LimitMaxDrawBuffersForTesting), |
| ES2_VULKAN() |
| .disable(Feature::SupportsTransformFeedbackExtension) |
| .disable(Feature::EmulateTransformFeedback)); |
| @@ -1791,3 +2850,51 @@ ANGLE_INSTANTIATE_TEST_ES3(DrawBuffersTestES3); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ColorMaskForDrawBuffersTest); |
| ANGLE_INSTANTIATE_TEST_ES3(ColorMaskForDrawBuffersTest); |
| + |
| +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBuffersAnyFormatTestES3); |
| + |
| +const angle::PlatformParameters kDrawBuffersAnyFormatPlatforms[] = { |
| + ANGLE_ALL_TEST_PLATFORMS_ES3, |
| + ES3_VULKAN().enable(Feature::ForceFallbackFormat), |
| + ES3_VULKAN().enable(Feature::PreferDrawClearOverVkCmdClearAttachments), |
| +}; |
| + |
| +INSTANTIATE_TEST_SUITE_P( |
| + NonMSAA, |
| + DrawBuffersAnyFormatTestES3, |
| + testing::Combine( |
| + testing::ValuesIn(::angle::FilterTestParams(kDrawBuffersAnyFormatPlatforms, |
| + ArraySize(kDrawBuffersAnyFormatPlatforms))), |
| + testing::ValuesIn(kDrawBuffersAnyFormatColorFormats), |
| + testing::ValuesIn(kDrawBuffersAnyFormatDepthStencilFormats), |
| + testing::Bool(), |
| + testing::Values<GLint>(0)), |
| + DrawBuffersAnyFormatVariationsTestPrint); |
| + |
| +INSTANTIATE_TEST_SUITE_P( |
| + MSAA, |
| + DrawBuffersAnyFormatTestES3, |
| + testing::Combine( |
| + testing::ValuesIn(::angle::FilterTestParams(kDrawBuffersAnyFormatPlatforms, |
| + ArraySize(kDrawBuffersAnyFormatPlatforms))), |
| + testing::ValuesIn(kDrawBuffersAnyFormatMSAAColorFormats), |
| + testing::ValuesIn(kDrawBuffersAnyFormatDepthStencilFormats), |
| + testing::Values(false), // renderbuffers only; ES 3.0 has no MSAA textures |
| + testing::Values<GLint>(2, 4)), |
| + DrawBuffersAnyFormatVariationsTestPrint); |
| + |
| +#if !ANGLE_PLATFORM_IOS_FAMILY |
| +// List MSAA8 in its own instantiation, so it's easier to understand that it's frequently |
| +// skipped. |
| +INSTANTIATE_TEST_SUITE_P( |
| + MSAA8, |
| + DrawBuffersAnyFormatTestES3, |
| + testing::Combine( |
| + testing::ValuesIn(::angle::FilterTestParams(kDrawBuffersAnyFormatPlatforms, |
| + ArraySize(kDrawBuffersAnyFormatPlatforms))), |
| + testing::ValuesIn(kDrawBuffersAnyFormatMSAAColorFormats), |
| + testing::ValuesIn(kDrawBuffersAnyFormatDepthStencilFormats), |
| + testing::Values(false), // renderbuffers only; ES 3.0 has no MSAA textures |
| + testing::Values<GLint>(kDrawBuffersAnyFormatMaxTestedSampleCount)), |
| + DrawBuffersAnyFormatVariationsTestPrint); |
| +#endif |
| diff --git a/src/tests/gl_tests/GLSLOutputTest.cpp b/src/tests/gl_tests/GLSLOutputTest.cpp |
| index 2cee83320b8a27eaf8c92d7eca43a2bbf128e83b..63cf419084462cb5cde09cae658514519ea4a459 100644 |
| --- a/src/tests/gl_tests/GLSLOutputTest.cpp |
| +++ b/src/tests/gl_tests/GLSLOutputTest.cpp |
| @@ -614,6 +614,7 @@ void main() { |
| "for (int i = 0; float(i) < 10e10; ++i) { }", |
| "for (int i = 0; i < 10; i++) { for (int j = 0; j < 1000; ++i) { }}", |
| "for (int i = 0; i != 1; i+=2) { }", |
| + "uint i; for (i = 0u; i < 10u; i++) { for (i = 0u; i < 0u; i++) { } }", |
| "for (int i = 0; i < 10; i++) { int j; for (j = 0, i = 0; j < 10; j++) { } }", |
| "for (int i = 0; i < 10; i++) { for (int j = 0; i = 0, j < 10; j++) { } }", |
| "for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; i = 0, j++) { } }", |
| @@ -624,6 +625,7 @@ void main() { |
| |
| for (const char *test : kTests) |
| { |
| + SCOPED_TRACE(testing::Message() << "test: " << test); |
| std::string shader = (std::stringstream() << kShaderPrefix << test << kShaderSuffix).str(); |
| compileShader(GL_FRAGMENT_SHADER, shader.c_str()); |
| verifyIsInTranslation(GL_FRAGMENT_SHADER, "loopForwardProgress"); |
| diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp |
| index 31eb8843e0bcb20d255380352c7978ad470c72ad..d812be7d0dc2d6e9b5c8de22b5a785ac449fd1ba 100644 |
| --- a/src/tests/gl_tests/GLSLTest.cpp |
| +++ b/src/tests/gl_tests/GLSLTest.cpp |
| @@ -808,6 +808,29 @@ TEST_P(GLSLTest, SwizzledChainedAssignIncrement) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(75, 75, 38, 38)); |
| } |
| |
| +// This shader uses chained assign-equals ops with swizzle, often reusing the same variable |
| +// as part of a swizzle, ivec variant |
| +TEST_P(GLSLTest, SwizzledChainedAssignIncrementIvec) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision mediump float; |
| +void main() { |
| + ivec2 v = ivec2(1,5); |
| + // at the end of next statement, values in |
| + // v.x = 12, v.y = 12 |
| + v.xy += v.yx += v.xy; |
| + // v1 and v2, both are initialized with (12,12) |
| + ivec2 v1 = v, v2 = v; |
| + v1.xy += v2.yx += ++(v.xy); // v1 = 37, v2 = 25 each |
| + v1.xy += v2.yx += (v.xy)++; // v1 = 75, v2 = 38 each |
| + gl_FragColor = vec4(vec2(v1),vec2(v2))/255.; // 75, 75, 38, 38 |
| +})"; |
| + ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS); |
| + drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); |
| + ASSERT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(75, 75, 38, 38)); |
| +} |
| + |
| // Same test as above without unary increments. |
| TEST_P(GLSLTest, SwizzledChainedAssign) |
| { |
| @@ -7202,6 +7225,94 @@ void main() |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| +// Tests that extracting samplers from structs that are members of other structs |
| +// will not cause a error when accessing any fields (e.g., uni.b) |
| +// (This is a modification of the above test "SamplerInStructMemberIndexing"). |
| +TEST_P(GLSLTest, SamplerInStructInStructMemberIndexing) |
| +{ |
| + const char kVertexShader[] = R"(attribute vec2 position; |
| +varying vec2 texCoord; |
| +void main() |
| +{ |
| + gl_Position = vec4(position, 0, 1); |
| + texCoord = position * 0.5 + vec2(0.5); |
| +})"; |
| + |
| + const char kFragmentShader[] = R"(precision mediump float; |
| +struct S1 { sampler2D samp; }; |
| +struct S2 { S1 s1; bool b; }; |
| +uniform S2 uni; |
| +varying vec2 texCoord; |
| +void main() |
| +{ |
| + uni; |
| + if (uni.b) |
| + { |
| + gl_FragColor = texture2D(uni.s1.samp, texCoord); |
| + } |
| + else |
| + { |
| + gl_FragColor = vec4(1, 0, 0, 1); |
| + } |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, kVertexShader, kFragmentShader); |
| + glUseProgram(program); |
| + |
| + GLint bLoc = glGetUniformLocation(program, "uni.b"); |
| + ASSERT_NE(-1, bLoc); |
| + GLint sampLoc = glGetUniformLocation(program, "uni.s1.samp"); |
| + ASSERT_NE(-1, sampLoc); |
| + |
| + glUniform1i(bLoc, 1); |
| + |
| + std::array<GLColor, 4> kGreenPixels = { |
| + {GLColor::green, GLColor::green, GLColor::green, GLColor::green}}; |
| + |
| + GLTexture tex; |
| + glBindTexture(GL_TEXTURE_2D, tex); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + kGreenPixels.data()); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + drawQuad(program, "position", 0.5f); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| +} |
| + |
| +// Tests that rewriting samplers in structs works when passed as function argument. In this test, |
| +// the function references another struct, which is not being modified. Regression test for AST |
| +// validation applied to a multipass transformation, where references to declarations were attempted |
| +// to be validated without having the entire shader. In this case, the reference to S2 was flagged |
| +// as invalid because S2's declaration was not visible. |
| +TEST_P(GLSLTest, SamplerInStructAsFunctionArg) |
| +{ |
| + const char kFS[] = R"(precision mediump float; |
| +struct S { sampler2D samp; bool b; }; |
| +struct S2 { float f; }; |
| + |
| +uniform S us; |
| + |
| +float f(S s) |
| +{ |
| + S2 s2; |
| + s2.f = float(s.b); |
| + return s2.f; |
| +} |
| + |
| +void main() |
| +{ |
| + gl_FragColor = vec4(f(us), 0, 0, 1); |
| +})"; |
| + |
| + GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS); |
| + EXPECT_NE(fs, 0u); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| // Test that nested structs with samplers work when the nested struct is not the last element. |
| TEST_P(GLSLTest_ES3, NestedStructWithSamplers) |
| { |
| @@ -11181,6 +11292,43 @@ void main() |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| } |
| |
| +// Test that modf(u, v.x) works correctly. |
| +TEST_P(GLSLTest_ES3, ModFIntegerToSwizzle) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp float; |
| +out vec4 o; |
| +uniform vec2 u; |
| +bool isEq(vec2 a, vec2 b) { return all(lessThan(abs(a-b), vec2(0.001))); } |
| +void main() |
| +{ |
| + vec4 i1; |
| + vec2 r1 = modf(u, i1.xy); |
| + vec2 r2; |
| + r2.x = modf(u.x, i1.z); |
| + r2.y = modf(u.y, i1.w); |
| + vec2 i2; |
| + vec2 r4 = modf(u, i2.yx); |
| + |
| + o = vec4(0.0, 0.0, 0.0, 1.0); |
| + if (isEq(r1, vec2(0.14, 0.15)) && isEq(i1.xy, vec2(3.0, 4.0))) |
| + o.r = 1.0; |
| + if (isEq(r2, vec2(0.14, 0.15)) && isEq(i1.zw, vec2(3.0, 4.0))) |
| + o.g = 1.0; |
| + if (isEq(r4, vec2(0.14, 0.15)) && isEq(i2, vec2(4.0, 3.0))) |
| + o.b = 1.0; |
| +})"; |
| + ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| + glUseProgram(program); |
| + ASSERT_GL_NO_ERROR(); |
| + GLint uloc = glGetUniformLocation(program, "u"); |
| + ASSERT_NE(uloc, -1); |
| + glUniform2f(uloc, 3.14f, 4.15f); |
| + drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f); |
| + ASSERT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); |
| +} |
| + |
| // Test a fragment shader that returns inside if (that being the only branch that actually gets |
| // executed). Regression test for http://anglebug.com/42261034 |
| TEST_P(GLSLTest, IfElseIfAndReturn) |
| @@ -22659,6 +22807,830 @@ void main() |
| ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS); |
| drawQuad(program, essl1_shaders::PositionAttrib(), 0.0); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| +} |
| + |
| +// Verify that missing fragment output components are zero-initialized |
| +TEST_P(WebGL2GLSLTest, InitMissingFragmentOutputComponents) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp float; |
| +layout(location = 0) out float outColor; |
| +void main() |
| +{ |
| + outColor = 1.0; |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| + drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 0, 0, 0)); |
| +} |
| + |
| +// Test highp int scalar + vec |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingAdd1) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u + ivec4(0, -1, 1, 2147483645); |
| + o.r = r.x == 2 ? 1.0 : 0.0; |
| + o.g = r.y == 1 ? 1.0 : 0.0; |
| + o.b = r.z == 3 ? 1.0 : 0.0; |
| + o.a = r.w == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec + scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingAdd2) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, 2147483645) + u; |
| + o.r = r.x == 2 ? 1.0 : 0.0; |
| + o.g = r.y == 1 ? 1.0 : 0.0; |
| + o.b = r.z == 3 ? 1.0 : 0.0; |
| + o.a = r.w == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec += scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingAdd3) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, 2147483645); |
| + r += u; |
| + o.r = r.x == 2 ? 1.0 : 0.0; |
| + o.g = r.y == 1 ? 1.0 : 0.0; |
| + o.b = r.z == 3 ? 1.0 : 0.0; |
| + o.a = r.w == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar + vec handles UB |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingAddUB) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u + ivec4(0, -1, 1, 2147483647); |
| + o.r = r.x == 2 ? 1.0 : 0.0; |
| + o.g = r.y == 1 ? 1.0 : 0.0; |
| + o.b = r.z == 3 ? 1.0 : 0.0; |
| + o.a = r.w == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar - vec |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingSub1) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u - ivec4(0, -1, 1, 2147483647); |
| + o.r = r.x == 2 ? 1.0 : 0.0; |
| + o.g = r.y == 3 ? 1.0 : 0.0; |
| + o.b = r.z == 1 ? 1.0 : 0.0; |
| + o.a = r.w == -2147483645 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec - scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingSub2) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, -2147483646) - u; |
| + o.r = r.x == -2 ? 1.0 : 0.0; |
| + o.g = r.y == -3 ? 1.0 : 0.0; |
| + o.b = r.z == -1 ? 1.0 : 0.0; |
| + o.a = r.w == -2147483648 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec -= scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingSub3) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, -2147483646); |
| + r -= u; |
| + o.r = r.x == -2 ? 1.0 : 0.0; |
| + o.g = r.y == -3 ? 1.0 : 0.0; |
| + o.b = r.z == -1 ? 1.0 : 0.0; |
| + o.a = r.w == -2147483648 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| +// |
| +// Test highp int scalar - vec handles UB |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingSubUB) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, -2147483648) - u; |
| + o.r = r.x == -2 ? 1.0 : 0.0; |
| + o.g = r.y == -3 ? 1.0 : 0.0; |
| + o.b = r.z == -1 ? 1.0 : 0.0; |
| + o.a = r.w == 2147483646 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar * vec |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingMul1) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u * ivec4(0, -1, 1, 3); |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == -2 ? 1.0 : 0.0; |
| + o.b = r.z == 2 ? 1.0 : 0.0; |
| + o.a = r.w == 6 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec * scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingMul2) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, 3) * u; |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == -2 ? 1.0 : 0.0; |
| + o.b = r.z == 2 ? 1.0 : 0.0; |
| + o.a = r.w == 6 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec *= scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingMul3) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, 3); |
| + r *= u; |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == -2 ? 1.0 : 0.0; |
| + o.b = r.z == 2 ? 1.0 : 0.0; |
| + o.a = r.w == 6 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar * vector handles UB |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingMulUB) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u * ivec4(0, -1, 1, -2147483648); |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == 1 ? 1.0 : 0.0; |
| + o.b = r.z == -1 ? 1.0 : 0.0; |
| + o.a = r.w == -2147483648 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, -1); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar / vec |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingDiv1) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u / ivec4(2, -1, 1, 3); |
| + o.r = r.x == 1 ? 1.0 : 0.0; |
| + o.g = r.y == -2 ? 1.0 : 0.0; |
| + o.b = r.z == 2 ? 1.0 : 0.0; |
| + o.a = r.w == 0 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec / scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingDiv2) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(2, -1, 1, 3) / u; |
| + o.r = r.x == 1 ? 1.0 : 0.0; |
| + o.g = r.y == 0 ? 1.0 : 0.0; |
| + o.b = r.z == 0 ? 1.0 : 0.0; |
| + o.a = r.w == 1 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec /= scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingDiv3) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(2, -1, 1, 3); |
| + r /= u; |
| + o.r = r.x == 1 ? 1.0 : 0.0; |
| + o.g = r.y == 0 ? 1.0 : 0.0; |
| + o.b = r.z == 0 ? 1.0 : 0.0; |
| + o.a = r.w == 1 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar / vec handles UB |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingDivUB) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u / ivec4(0, -1, 1, 3); |
| + o.r = r.x == -2147483648 ? 1.0 : 0.0; |
| + // FIXME: ANGLE_div should also handle -INT_MAX / -1 |
| + // o.g = r.y == -2147483648 ? 1.0 : 0.0; |
| + o.g = 1.0; |
| + o.b = r.z == -2147483648 ? 1.0 : 0.0; |
| + o.a = r.w == -715827882 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, -2147483648); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar % vec |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingMod1) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u % ivec4(2, 7, 1, 3); |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == 2 ? 1.0 : 0.0; |
| + o.b = r.z == 0 ? 1.0 : 0.0; |
| + o.a = r.w == 2 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec % scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingMod2) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(2147483647, 0, 1, 3) % u; |
| + o.r = r.x == 1 ? 1.0 : 0.0; |
| + o.g = r.y == 0 ? 1.0 : 0.0; |
| + o.b = r.z == 1 ? 1.0 : 0.0; |
| + o.a = r.w == 1 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec %= scalar |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingMod3) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(2147483647, 0, 1, 3); |
| + r %= u; |
| + o.r = r.x == 1 ? 1.0 : 0.0; |
| + o.g = r.y == 0 || r.y == 1 ? 1.0 : 0.0; |
| + o.b = r.z == 1 ? 1.0 : 0.0; |
| + o.a = r.w == 1 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int scalar % vec handles UB |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingModUB) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = u % ivec4(0, -1, 1, 3); |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == 0 ? 1.0 : 0.0; |
| + o.b = r.z == 0 ? 1.0 : 0.0; |
| + o.a = r.w == -2 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, -2147483648); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int float to int vector conversion |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingFtoi1) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform vec4 u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(u); |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == -1 ? 1.0 : 0.0; |
| + o.b = r.z == -2147483648 ? 1.0 : 0.0; |
| + o.a = r.w == 83645 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4f(u, 0., -1., -2147483648., 83645.); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int float to int scalar conversion |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingFtoi2) |
| +{ |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform vec4 u; |
| +out vec4 o; |
| +void main() { |
| + int rx = int(u.x); |
| + int ry = int(u.y); |
| + int rz = int(u.z); |
| + int rw = int(u.w); |
| + o.r = rx == 0 ? 1.0 : 0.0; |
| + o.g = ry == -1 ? 1.0 : 0.0; |
| + o.b = rz == -2147483648 ? 1.0 : 0.0; |
| + o.a = rw == 83645 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4f(u, 0., -1., -2147483648., 83645.); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| +// |
| +// Test highp int float to int vector conversion handles UB |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingFtoiUB1) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform vec4 u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(u); |
| + o.r = r.x == 0 ? 1.0 : 0.0; |
| + o.g = r.y == -1 ? 1.0 : 0.0; |
| + o.b = r.z == -2147483648 ? 1.0 : 0.0; |
| + o.a = r.w == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4f(u, 0., -1., -2147483649., 2147483648.); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int float to int scalar conversion handles UB |
| +TEST_P(GLSLTest_ES3, IntVecOperatorOverloadingFtoiUB2) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform vec4 u; |
| +out vec4 o; |
| +void main() { |
| + int rx = int(u.x); |
| + int ry = int(u.y); |
| + int rz = int(u.z); |
| + int rw = int(u.w); |
| + o.r = rx == 0 ? 1.0 : 0.0; |
| + o.g = ry == -1 ? 1.0 : 0.0; |
| + o.b = rz == -2147483648 ? 1.0 : 0.0; |
| + o.a = rw == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4f(u, 0., -1., -2147483649., 2147483648.); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int wrap behavior with plus and minus. |
| +TEST_P(GLSLTest_ES3, IntVecAdditionSubtractionWrap) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(u) + ivec4(0, -1, 1, 3); |
| + r -= ivec4(2147483647, 2147483647, 2147483647, 0); |
| + r += ivec4(0, 0, 0, 2147483647); |
| + o.r = r.x == -2147483647 ? 1.0 : 0.0; |
| + o.g = r.y == -2147483648 ? 1.0 : 0.0; |
| + o.b = r.z == -2147483646 ? 1.0 : 0.0; |
| + o.a = r.w == -2147483646 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int wrap behavior with multiplication. |
| +TEST_P(GLSLTest_ES3, IntVecMultiplicationWrap) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(u) + ivec4(-2, 2, 1, -1); |
| + r *= ivec4(2147483647, 2147483647, -2147483648, -2147483648); |
| + o.r = r.x == 2 ? 1.0 : 0.0; |
| + o.g = r.y == -2 ? 1.0 : 0.0; |
| + o.b = r.z == -2147483648 ? 1.0 : 0.0; |
| + o.a = r.w == -2147483648 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int wrap behavior with division. |
| +TEST_P(GLSLTest_ES3, IntVecDivisionWrap) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(u) + ivec4(2147483647, 2147483647, -2147483648, -2147483648); |
| + r /= ivec4(1, -1, 1, -1); |
| + o.r = r.x == 2147483647 ? 1.0 : 0.0; |
| + o.g = r.y == -2147483647 ? 1.0 : 0.0; |
| + o.b = r.z == -2147483648 ? 1.0 : 0.0; |
| + o.a = 1.0; |
| + |
| + // FIXME |
| + //o.a = r.w == -2147483648 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int wrap behavior with modulus. |
| +TEST_P(GLSLTest_ES3, IntScalarModulus) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(u) + ivec4(2147483647, 2147483647, -2147483648, -2147483648); |
| + r %= 8; |
| + o.r = r.x == 7 ? 1.0 : 0.0; |
| + o.g = r.y == 7 ? 1.0 : 0.0; |
| + o.b = r.z == 0 ? 1.0 : 0.0; |
| + o.a = r.w == 0 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int modulus undefinedness with negative numbers |
| +TEST_P(GLSLTest_ES3, IntScalarModulusUB1) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!IsMetal()); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +out vec4 o; |
| +void main() { |
| + ivec4 r = ivec4(u) + ivec4(-1, 1, -7, 7); |
| + r %= 8; |
| + o.r = r.x == -1 ? 1.0 : 0.0; |
| + o.g = r.y == 1 ? 1.0 : 0.0; |
| + o.b = r.z == -7 ? 1.0 : 0.0; |
| + o.a = r.w == 7 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + drawQuad(testProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| diff --git a/src/tests/gl_tests/GLSLUBTest.cpp b/src/tests/gl_tests/GLSLUBTest.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..07d0c1c6fdb07a6661f086356fbe39fdfaccb57e |
| --- /dev/null |
| +++ b/src/tests/gl_tests/GLSLUBTest.cpp |
| @@ -0,0 +1,619 @@ |
| +// |
| +// Copyright 2025 The ANGLE Project Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| +// |
| + |
| +#include "test_utils/ANGLETest.h" |
| + |
| +#include "test_utils/angle_test_configs.h" |
| +#include "test_utils/gl_raii.h" |
| +#include "util/shader_utils.h" |
| + |
| +namespace |
| +{ |
| +using namespace angle; |
| + |
| +class GLSLUBTest : public ANGLETest<> |
| +{ |
| + protected: |
| + GLSLUBTest() |
| + { |
| + setWindowWidth(128); |
| + setWindowHeight(128); |
| + setConfigRedBits(8); |
| + setConfigGreenBits(8); |
| + setConfigBlueBits(8); |
| + setConfigAlphaBits(8); |
| + } |
| +}; |
| + |
| +// grep TEST_P src/tests/gl_tests/GLSLUBTest.cpp |
| +// For prefixes Add, Sub find: |
| +// IntInt |
| +// IntIvec |
| +// IvecInt |
| +// IvecIvec |
| +// AssignIvecInt |
| +// AssignIvecIvec |
| + |
| +// Test int + int with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, AddIntIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + int r0 = u + -1; |
| + int r1 = u + 0; |
| + int r2 = 2147483646 + u; |
| + int r3 = u + 2147483647; |
| + |
| + gl_FragColor.r = r0 == 1 ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == 2 ? 1.0 : 0.0; |
| + gl_FragColor.b = r2 == -2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.a = r3 == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test int + ivec overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, AddIntIvecOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + ivec4 r = u + ivec4(0, -1, 1, 2147483647); |
| + gl_FragColor.r = r.x == 2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == 1 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == 3 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test int + ivec overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, AddIvecIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, 2147483647) + u; |
| + gl_FragColor.r = r.x == 2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == 1 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == 3 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test ivec + ivec, ivec + int overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, AddIvecIvecOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform ivec4 u; |
| +void main() { |
| + ivec4 r0 = u + ivec4(0, -1, 1, 2147483647); |
| + ivec4 r1 = ivec4(0, -1, 1, 2147483647) + u; |
| + gl_FragColor.r = r0 == r1 ? 1.0 : 0.0; |
| + gl_FragColor.g = r0.y == 1 ? 1.0 : 0.0; |
| + gl_FragColor.b = r0.z == 3 ? 1.0 : 0.0; |
| + gl_FragColor.a = r0.w == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4i(u, 2, 2, 2, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp ivec += int overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, AddAssignIvecIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, 2147483647); |
| + r += u; |
| + gl_FragColor.r = r.x == 2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == 1 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == 3 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp ivec += ivec overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, AddAssignIvecIvecOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform ivec4 u; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, 2147483647); |
| + r += u; |
| + gl_FragColor.r = r.x == 2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == 1 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == 3 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4i(u, 2, 2, 2, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test int - int with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, SubIntIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + int r0 = u - (-1); |
| + int r1 = u - 0; |
| + int r2 = -2147483646 - u; |
| + int r3 = u - (-2147483647); |
| + |
| + gl_FragColor.r = r0 == 3 ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == 2 ? 1.0 : 0.0; |
| + gl_FragColor.b = r2 == 2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.a = r3 == -2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int - ivec underflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, SubIntIvecUnderflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + ivec4 r = u - ivec4(0, -1, 1, 2147483647); |
| + gl_FragColor.r = r.x == 2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == 3 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == 1 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == -2147483645 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp ivec - int underflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, SubIvecIntUnderflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, -2147483647) - u; |
| + gl_FragColor.r = r.x == -2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == -3 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == -1 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec -= scalar underflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, SubAssignIvecIntUnderflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, -2147483647); |
| + r -= u; |
| + gl_FragColor.r = r.x == -2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == -3 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == -1 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test highp int vec -= scalar underflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, SubAssignIvecIvecUnderflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform ivec4 u; |
| +void main() { |
| + ivec4 r = ivec4(0, -1, 1, -2147483647); |
| + r -= u; |
| + gl_FragColor.r = r.x == -2 ? 1.0 : 0.0; |
| + gl_FragColor.g = r.y == -3 ? 1.0 : 0.0; |
| + gl_FragColor.b = r.z == -1 ? 1.0 : 0.0; |
| + gl_FragColor.a = r.w == 2147483647 ? 1.0 : 0.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4i(u, 2, 2, 2, 2); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test ++int with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PreIncrementIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + int r0 = u; |
| + int r1 = ++r0; |
| + |
| + gl_FragColor.r = r0 == -2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == -2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.b = u == 2147483647 ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test int++ with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PostIncrementIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + int r0 = u; |
| + int r1 = r0++; |
| + |
| + gl_FragColor.r = r0 == -2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == 2147483647 ? 1.0 : 0.0; |
| + gl_FragColor.b = u == 2147483647 ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test --int with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PreDecrementIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + int r0 = u; |
| + int r1 = --r0; |
| + |
| + gl_FragColor.r = r0 == 2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == 2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.b = u == -2147483647 ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, -2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test int-- with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PostDecrementIntOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + int r0 = u; |
| + int r1 = r0--; |
| + |
| + gl_FragColor.r = r0 == 2147483648 ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == -2147483647 ? 1.0 : 0.0; |
| + gl_FragColor.b = u == -2147483647 ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, -2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test ++ivec with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PreIncrementIvecOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform ivec4 u; |
| +void main() { |
| + ivec4 r0 = u; |
| + ivec4 r1 = ++r0; |
| + |
| + gl_FragColor.r = r0 == ivec4(1, 2, 3, -2147483648) ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == ivec4(1, 2, 3, -2147483648) ? 1.0 : 0.0; |
| + gl_FragColor.b = u == ivec4(0, 1, 2, 2147483647) ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4i(u, 0, 1, 2, 2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| +// Test ivec++ with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PostIncrementIvecOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform ivec4 u; |
| +void main() { |
| + ivec4 r0 = u; |
| + ivec4 r1 = r0++; |
| + |
| + gl_FragColor.r = r0 == ivec4(1, 2, 3, -2147483648) ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == ivec4(0, 1, 2, 2147483647) ? 1.0 : 0.0; |
| + gl_FragColor.b = u == ivec4(0, 1, 2, 2147483647) ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4i(u, 0, 1, 2, 2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test --ivec with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PreDecrementIvecOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform ivec4 u; |
| +void main() { |
| + ivec4 r0 = u; |
| + ivec4 r1 = --r0; |
| + |
| + gl_FragColor.r = r0 == ivec4(-1, 0, 1, 2147483648) ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == ivec4(-1, 0, 1, 2147483648) ? 1.0 : 0.0; |
| + gl_FragColor.b = u == ivec4(0, 1, 2, -2147483647) ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4i(u, 0, 1, 2, -2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test ivec-- with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PostDecrementIvecOverflow) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform ivec4 u; |
| +void main() { |
| + ivec4 r0 = u; |
| + ivec4 r1 = r0--; |
| + |
| + gl_FragColor.r = r0 == ivec4(-1, 0, 1, 2147483648) ? 1.0 : 0.0; |
| + gl_FragColor.g = r1 == ivec4(0, 1, 2, -2147483647) ? 1.0 : 0.0; |
| + gl_FragColor.b = u == ivec4(0, 1, 2, -2147483647) ? 1.0 : 0.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform4i(u, 0, 1, 2, -2147483647); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test int++ with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PostIncrementIntOverflowInForDynamic) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +uniform int u; |
| +void main() { |
| + int z = 0; |
| + for (int i = u; i > 4; i++) { |
| + z++; |
| + } |
| + gl_FragColor.r = z == 7 ? 1.0 : 0.0; |
| + gl_FragColor.g = u == 2147483641 ? 1.0 : 0.0; |
| + gl_FragColor.b = 1.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + GLint u = glGetUniformLocation(testProgram, "u"); |
| + EXPECT_NE(-1, u); |
| + glUniform1i(u, 2147483641); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test int++ with overflow. Expect wraparound. |
| +TEST_P(GLSLUBTest, PostIncrementIntOverflowInForStatic) |
| +{ |
| + constexpr char kFS[] = R"( |
| +precision highp int; |
| +precision highp float; |
| +void main() { |
| + int z = 0; |
| + for (int i = 2147483642; i > 4; i++) { |
| + z++; |
| + } |
| + gl_FragColor.r = z == 6 ? 1.0 : 0.0; |
| + gl_FragColor.g = 1.0; |
| + gl_FragColor.b = 1.0; |
| + gl_FragColor.a = 1.0; |
| +} |
| +)"; |
| + ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(testProgram); |
| + drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255)); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +} // anonymous namespace |
| + |
| +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLUBTest); |
| +ANGLE_INSTANTIATE_TEST(GLSLUBTest, ES2_METAL(), ES3_METAL()); |
| diff --git a/src/tests/gl_tests/ImageTestMetal.mm b/src/tests/gl_tests/ImageTestMetal.mm |
| index 4345af3a936bd0bead825e2a8ea5fa82fe5dd562..69048754a60ee3344d25f2f67ffe18a911f00df4 100644 |
| --- a/src/tests/gl_tests/ImageTestMetal.mm |
| +++ b/src/tests/gl_tests/ImageTestMetal.mm |
| @@ -16,7 +16,6 @@ |
| |
| #include <CoreFoundation/CoreFoundation.h> |
| #include <Metal/Metal.h> |
| -#include <gmock/gmock.h> |
| #include <span> |
| |
| namespace angle |
| @@ -120,10 +119,14 @@ bool IsDepthOrStencil(MTLPixelFormat format) |
| case MTLPixelFormatDepth16Unorm: |
| case MTLPixelFormatDepth32Float: |
| case MTLPixelFormatStencil8: |
| +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| case MTLPixelFormatDepth24Unorm_Stencil8: |
| +#endif |
| case MTLPixelFormatDepth32Float_Stencil8: |
| case MTLPixelFormatX32_Stencil8: |
| +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| case MTLPixelFormatX24_Stencil8: |
| +#endif |
| return true; |
| |
| default: |
| @@ -345,8 +348,12 @@ class ImageTestMetal : public ANGLETest<> |
| |
| bool hasDepth24Stencil8PixelFormat() |
| { |
| + #if TARGET_OS_OSX || TARGET_OS_MACCATALYST |
| id<MTLDevice> device = getMtlDevice(); |
| return device.depth24Stencil8PixelFormatSupported; |
| + #else |
| + return false; |
| + #endif |
| } |
| |
| bool hasImageNativeMetalTextureExt() const |
| diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp |
| index d15ba1f5e6fa2722eb05c3d5ee4028a3bce7b251..7891d0e3e9b932f76bcdbeaae157959ddad5ae73 100644 |
| --- a/src/tests/gl_tests/MipmapTest.cpp |
| +++ b/src/tests/gl_tests/MipmapTest.cpp |
| @@ -2214,6 +2214,31 @@ TEST_P(MipmapTestES3, GenerateMipmapWithRedefineLevelAndTexture) |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::black); |
| } |
| |
| +// Test that generating mipmaps after defining an incompatible image out of base-max range |
| +// does not cause problems. At the time of writing with Metal backend, defining images |
| +// after one state sync would cause problems upon subsequent GenerateMipmaps(). |
| +TEST_P(MipmapTestES3, GenerateMipmapWithOutOfRangeLevelDefinition) |
| +{ |
| + GLTexture texture; |
| + glBindTexture(GL_TEXTURE_2D, texture); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + |
| + std::vector<GLColor> data(2 * 2, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + data.data()); |
| + glGenerateMipmap(GL_TEXTURE_2D); // Sync state. |
| + glTexImage2D(GL_TEXTURE_2D, 10, GL_DEPTH_COMPONENT32F, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, |
| + nullptr); // Trigger the bug. |
| + EXPECT_GL_NO_ERROR(); |
| + glGenerateMipmap(GL_TEXTURE_2D); // At the time, this would fail. |
| + EXPECT_GL_NO_ERROR(); |
| + |
| + clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight()); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green); |
| +} |
| + |
| // Test that manually generating mipmaps using draw calls is functional |
| TEST_P(MipmapTestES31, GenerateMipmapWithDraw) |
| { |
| @@ -2657,6 +2682,82 @@ TEST_P(MipmapTestES3, MismatchingLevelFormats3) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan); |
| } |
| |
| +// Verifies texture uploads work correctly after size transitions that change mipmap dimensions. |
| +TEST_P(MipmapTest, UploadAfterSizeTransition) |
| +{ |
| + GLTexture texture; |
| + glBindTexture(GL_TEXTURE_2D, texture); |
| + |
| + std::vector<GLColor> redData(128 * 128, GLColor::red); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + redData.data()); |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + std::vector<GLColor> greenData(256 * 256, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + greenData.data()); |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + std::vector<GLColor> blueData(128 * 128, GLColor::blue); |
| + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + blueData.data()); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(128, 128, GLColor::green); |
| + |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::blue); |
| +} |
| + |
| +// Verifies old generated mipmap data doesn't persist after base level size changes. |
| +TEST_P(MipmapTest, GeneratedMipmapsInvalidatedAfterSizeChange) |
| +{ |
| + GLTexture texture; |
| + glBindTexture(GL_TEXTURE_2D, texture); |
| + |
| + std::vector<GLColor> redData(128 * 128, GLColor::red); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + redData.data()); |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::red); |
| + |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(32, 32, GLColor::red); |
| + |
| + std::vector<GLColor> greenData(256 * 256, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + greenData.data()); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(128, 128, GLColor::green); |
| + |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 1); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::green); |
| +} |
| + |
| + |
| // Use this to select which configurations (e.g. which renderer, which GLES major version) these |
| // tests should be run against. |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND( |
| diff --git a/src/tests/gl_tests/PbufferTest.cpp b/src/tests/gl_tests/PbufferTest.cpp |
| index 2c7cbb21165d268db8894eae582845511b59479a..6ded792cbcc590db2af1f5badc3882ae39878da0 100644 |
| --- a/src/tests/gl_tests/PbufferTest.cpp |
| +++ b/src/tests/gl_tests/PbufferTest.cpp |
| @@ -306,7 +306,6 @@ TEST_P(PbufferTest, BindTexImageOverwrite) |
| // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA |
| // textures. |
| ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage); |
| - |
| EGLWindow *window = getEGLWindow(); |
| window->makeCurrent(); |
| |
| @@ -584,7 +583,6 @@ TEST_P(PbufferTest, BindTexImageOverwriteReleasesOrphanedPbuffer) |
| // Test skipped because Pbuffers are not supported or Pbuffer does not support binding to RGBA |
| // textures. |
| ANGLE_SKIP_TEST_IF(!mSupportsPbuffers || !mSupportsBindTexImage); |
| - |
| EGLWindow *window = getEGLWindow(); |
| window->makeCurrent(); |
| |
| diff --git a/src/tests/gl_tests/PixelLocalStorageTest.cpp b/src/tests/gl_tests/PixelLocalStorageTest.cpp |
| index caf182dc4c0f3ab0d043b2e63b64b50a18bdefd7..d6ab58fadc05e5dc5516e46c3a90a53d8907c6ec 100644 |
| --- a/src/tests/gl_tests/PixelLocalStorageTest.cpp |
| +++ b/src/tests/gl_tests/PixelLocalStorageTest.cpp |
| @@ -6,7 +6,7 @@ |
| |
| #include <sstream> |
| #include <string> |
| -#include "common/unsafe_buffers.h" |
| +#include "common/string_utils.h" |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| |
| @@ -9602,7 +9602,6 @@ TEST_P(PixelLocalStorageCompilerTest, BlendEquationAdvanced_illegal_with_PLS) |
| layout(binding=0, rgba8i) uniform lowp ipixelLocalANGLE pls;)"; |
| EXPECT_TRUE(log.compileFragmentShader(kRequireBlendAdvanced)); |
| |
| - bool before = true; |
| for (const char *layoutQualifier : { |
| "blend_support_multiply", |
| "blend_support_screen", |
| @@ -9622,44 +9621,34 @@ TEST_P(PixelLocalStorageCompilerTest, BlendEquationAdvanced_illegal_with_PLS) |
| "blend_support_all_equations", |
| }) |
| { |
| - constexpr char kRequireBlendAdvancedBeforePLS[] = R"(#version 300 es |
| - #extension GL_ANGLE_shader_pixel_local_storage : require |
| - #extension GL_KHR_blend_equation_advanced : require |
| - layout(%s) out; |
| - void main() |
| - {} |
| - layout(binding=0, rgba8i) uniform lowp ipixelLocalANGLE pls;)"; |
| - |
| - constexpr char kRequireBlendAdvancedAfterPLS[] = R"(#version 300 es |
| - #extension GL_ANGLE_shader_pixel_local_storage : require |
| - #extension GL_KHR_blend_equation_advanced : require |
| - layout(binding=0, rgba8i) uniform lowp ipixelLocalANGLE pls; |
| - layout(%s) out; |
| - void main() |
| - {})"; |
| + std::string shaderBefore = R"(#version 300 es |
| +#extension GL_ANGLE_shader_pixel_local_storage : require |
| +#extension GL_KHR_blend_equation_advanced : require |
| +layout(%s) out; |
| +void main() |
| +{} |
| +layout(binding=0, rgba8i) uniform lowp ipixelLocalANGLE pls;)"; |
| + ReplaceSubstring(&shaderBefore, "%s", layoutQualifier); |
| |
| - const char *formatStr = |
| - before ? kRequireBlendAdvancedBeforePLS : kRequireBlendAdvancedAfterPLS; |
| - size_t buffSize = ANGLE_UNSAFE_TODO(snprintf(nullptr, 0, formatStr, layoutQualifier) + |
| - 1); // Extra space for '\0' |
| - std::unique_ptr<char[]> shader(new char[buffSize]); |
| - ANGLE_UNSAFE_TODO(std::snprintf(shader.get(), buffSize, formatStr, layoutQualifier)); |
| - EXPECT_FALSE(log.compileFragmentShader(shader.get())); |
| - if (before) |
| - { |
| + EXPECT_FALSE(log.compileFragmentShader(shaderBefore.c_str())); |
| EXPECT_TRUE( |
| log.has("ERROR: 0:4: 'layout' : illegal advanced blend equation when pixel local " |
| "storage is declared")); |
| - } |
| - else |
| - { |
| + |
| + std::string shaderAfter = R"(#version 300 es |
| +#extension GL_ANGLE_shader_pixel_local_storage : require |
| +#extension GL_KHR_blend_equation_advanced : require |
| +layout(binding=0, rgba8i) uniform lowp ipixelLocalANGLE pls; |
| +layout(%s) out; |
| +void main() |
| +{})"; |
| + ReplaceSubstring(&shaderAfter, "%s", layoutQualifier); |
| + |
| + EXPECT_FALSE(log.compileFragmentShader(shaderAfter.c_str())); |
| EXPECT_TRUE( |
| log.has("ERROR: 0:5: 'layout' : illegal advanced blend equation when pixel local " |
| "storage is declared")); |
| } |
| - |
| - before = !before; |
| - } |
| } |
| |
| // Check proper validation of PLS function arguments. |
| diff --git a/src/tests/gl_tests/ProvokingVertexTest.cpp b/src/tests/gl_tests/ProvokingVertexTest.cpp |
| index 314cae92deaef9b0eae11b4909415ef2fb91e11c..e05979cdc925b8ce5168b121504f5ce0f1c394be 100644 |
| --- a/src/tests/gl_tests/ProvokingVertexTest.cpp |
| +++ b/src/tests/gl_tests/ProvokingVertexTest.cpp |
| @@ -13,7 +13,6 @@ |
| #include "common/unsafe_buffers.h" |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| -#include "util/gles_loader_autogen.h" |
| |
| using namespace angle; |
| |
| diff --git a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp |
| index fcae00f2b1167dda52f8c857c8d94cc6c2eb7d98..a03f894e251fa90bcad100a9401b845b3a8f2a76 100644 |
| --- a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp |
| +++ b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp |
| @@ -43,7 +43,7 @@ class RobustBufferAccessBehaviorTest : public ANGLETest<> |
| { |
| return false; |
| } |
| - setWindowVisible(mOSWindow, true); |
| + setWindowVisible(mOSWindow, shouldShowWindow()); |
| |
| Library *driverLib = ANGLETestEnvironment::GetDriverLibrary(getDriverType()); |
| |
| diff --git a/src/tests/gl_tests/RobustResourceInitTest.cpp b/src/tests/gl_tests/RobustResourceInitTest.cpp |
| index 661b287a5be979de6409fa4836d2efb4f76c00ed..ed09ea1993198b9e278be6d7a82a527302e2f99a 100644 |
| --- a/src/tests/gl_tests/RobustResourceInitTest.cpp |
| +++ b/src/tests/gl_tests/RobustResourceInitTest.cpp |
| @@ -10,7 +10,6 @@ |
| |
| #include "test_utils/gl_raii.h" |
| #include "util/EGLWindow.h" |
| -#include "util/gles_loader_autogen.h" |
| |
| namespace angle |
| { |
| diff --git a/src/tests/gl_tests/SamplersTest.cpp b/src/tests/gl_tests/SamplersTest.cpp |
| index 91b896310757f302c3919ed69eb0c7c88f65836c..0d6dbbad3c024fb4a9d0b1ef085de354c46fcfa0 100644 |
| --- a/src/tests/gl_tests/SamplersTest.cpp |
| +++ b/src/tests/gl_tests/SamplersTest.cpp |
| @@ -12,7 +12,6 @@ |
| |
| #include "test_utils/angle_test_configs.h" |
| #include "test_utils/gl_raii.h" |
| -#include "util/gles_loader_autogen.h" |
| #include "util/shader_utils.h" |
| |
| namespace angle |
| diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp |
| index efcd5bd7eeda8ce547b0954ef3ddc5c707c352a6..d8fe86f56251b6295418204f17f2f9f76d8e1be6 100644 |
| --- a/src/tests/gl_tests/TextureTest.cpp |
| +++ b/src/tests/gl_tests/TextureTest.cpp |
| @@ -2010,6 +2010,7 @@ void Texture2DDepthStencilTestES3::TestSampleWithDepthStencilMode(GLenum format, |
| break; |
| default: |
| UNREACHABLE(); |
| + return; |
| } |
| |
| // Set up a color texture. |
| @@ -2375,7 +2376,37 @@ TEST_P(Texture2DTest, DefineMultipleLevelsWithoutMipmapping) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, kMipColors[0][0]); |
| } |
| |
| -// Test drawing with two texture types, regression test for an old bug in validation. |
| +// Test that glTexSubImage2D works after defining a incompatible image out of base-max range. |
| +TEST_P(Texture2DTestES3, TexSubImageWithOutOfRangeLevelDefinition) |
| +{ |
| + setUpProgram(); |
| + glActiveTexture(GL_TEXTURE0); |
| + glBindTexture(GL_TEXTURE_2D, mTexture2D); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + |
| + std::vector<GLColor> data(2 * 2, GLColor::red); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + data.data()); |
| + EXPECT_GL_NO_ERROR(); |
| + glGenerateMipmap(GL_TEXTURE_2D); // Sync state. |
| + glTexImage2D(GL_TEXTURE_2D, 10, GL_DEPTH_COMPONENT32F, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, |
| + nullptr); |
| + EXPECT_GL_NO_ERROR(); |
| + |
| + std::vector<GLColor> updateData(2 * 2, GLColor::green); |
| + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, |
| + updateData.data()); // Trigger the bug. |
| + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, |
| + updateData.data()); // Clean up the mipmap so test verification works. |
| + EXPECT_GL_NO_ERROR(); |
| + |
| + drawQuad(mProgram, "position", 0.0f); |
| + EXPECT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::green); |
| +} |
| + |
| +// Test drawing with two texture types, to trigger an ANGLE bug in validation |
| TEST_P(TextureCubeTest, CubeMapBug) |
| { |
| glActiveTexture(GL_TEXTURE0); |
| @@ -12604,7 +12635,7 @@ class TextureLimitsTest : public ANGLETest<> |
| initTextures(vertexTextureCount + fragmentTextureCount, 0); |
| |
| glUseProgram(mProgram); |
| - RGBA8 expectedSum = {0}; |
| + RGBA8 expectedSum{}; |
| for (GLint texIndex = 0; texIndex < vertexTextureCount; ++texIndex) |
| { |
| std::stringstream uniformNameStr; |
| @@ -13784,6 +13815,81 @@ TEST_P(Texture2DTestES3, UnpackSkipImages2D) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| +// Test that UNPACK_IMAGE_HEIGHT, GL_UNPACK_SKIP_IMAGES has no effect on TexImage2D. |
| +// Tests both PBO and pixel data variants. |
| +TEST_P(Texture2DTestES3, UnpackImageHeight2DDepth) |
| +{ |
| + const GLsizei width = 1; |
| + const GLsizei height = 512; |
| + const GLsizei dataSize = width * height; |
| + std::vector<GLfloat> bufferData(3 * dataSize, 0); |
| + for (GLsizei i = 0; i < dataSize; ++i) |
| + { |
| + bufferData[i] = 1.0f; |
| + } |
| + GLBuffer pbo; |
| + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); |
| + glBufferData(GL_PIXEL_UNPACK_BUFFER, bufferData.size() * sizeof(bufferData[0]), |
| + bufferData.data(), GL_STATIC_DRAW); |
| + |
| + struct |
| + { |
| + bool useUnpackBuffer; |
| + bool useImageHeight; |
| + bool useSkipImages; |
| + } subcases[]{{true, true, true}, {true, true, false}, {true, false, true}, |
| + {true, false, false}, {false, true, true}, {false, true, false}, |
| + {false, false, false}}; |
| + for (auto [useUnpackBuffer, useImageHeight, useSkipImages] : subcases) |
| + { |
| + SCOPED_TRACE(::testing::Message() << "unpackBuffer:" << useUnpackBuffer << " imageHeight:" |
| + << useImageHeight << " skipImages:" << useSkipImages); |
| + |
| + GLTexture texture; |
| + glBindTexture(GL_TEXTURE_2D, texture); |
| + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, useUnpackBuffer ? pbo : 0); |
| + void *data = useUnpackBuffer ? nullptr : bufferData.data(); |
| + |
| + // This is being tested: UNPACK_IMAGE_HEIGHT does not affect the TexImage2D. |
| + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, useImageHeight ? 128 : 0); |
| + glPixelStorei(GL_UNPACK_SKIP_IMAGES, useSkipImages ? 1 : 0); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, width, height, 0, GL_DEPTH_COMPONENT, |
| + GL_FLOAT, data); |
| + EXPECT_GL_NO_ERROR(); |
| + |
| + // Verify: depth buffer got populated from depth data and contains 1.0f. |
| + glViewport(0, 0, width, height); |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture, 0); |
| + GLTexture colorTexture; |
| + glBindTexture(GL_TEXTURE_2D, colorTexture); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + nullptr); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, |
| + 0); |
| + ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + EXPECT_GL_NO_ERROR(); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + |
| + glEnable(GL_DEPTH_TEST); |
| + |
| + // Verifies that depth test works. Buffer contains 1.0 elements, draw with depth test |
| + // produces nothing. |
| + glDepthFunc(GL_GREATER); |
| + ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| + drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.95f); |
| + EXPECT_PIXEL_RECT_EQ(0, 0, width, height, GLColor::transparentBlack); |
| + |
| + // Verifies that TexImage2D worked. Buffer contains 1.0 elements, draw with depth test |
| + // produces results. |
| + glDepthFunc(GL_LESS); |
| + drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.95f); |
| + EXPECT_PIXEL_RECT_EQ(0, 0, width, height, GLColor::green); |
| + EXPECT_GL_NO_ERROR(); |
| + } |
| +} |
| + |
| // Test that skip defined in unpack parameters is taken into account when determining whether |
| // unpacking source extends outside unpack buffer bounds. |
| TEST_P(Texture2DTestES3, UnpackSkipPixelsOutOfBounds) |
| @@ -18644,7 +18750,7 @@ TEST_P(Texture2DTestES3, LargeTextureOverflow) |
| } |
| |
| // Create an integer format texture but specify a FLOAT sampler. OpenGL |
| -// tolerates this but it causes a Vulkan validation error. |
| +// tolerates this but it causes a Vulkan and Metal validation error. |
| TEST_P(Texture2DTestES3, TexImageFormatMismatch) |
| { |
| GLint textureUnit = 2; |
| @@ -18745,6 +18851,172 @@ TEST_P(Texture2DTestES3, PackPixels3DAnd2DArrayTypeConfusion) |
| glUnmapBuffer(GL_PIXEL_PACK_BUFFER); |
| } |
| |
| +// Test that a stale per-level image view is not reused after native storage is recreated via the FBO path. |
| +TEST_P(Texture2DTestES3, StaleMipViewAfterFBOTriggeredStorageRecreation) |
| +{ |
| + GLTexture tex; |
| + glBindTexture(GL_TEXTURE_2D, tex); |
| + |
| + // Create 256x256 base, generate mipmaps to create native storage. |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Resize base to 512x512. Retains stale views of old storage in levels 1-8. |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Recreate native storage via getAttachmentRenderTarget (FBO attach + clear). |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Upload green to level 1. Must go to new native storage, not stale 128x128 view. |
| + std::vector<GLColor> greenPixels(256 * 256, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + greenPixels.data()); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Read back level 1 via FBO. Restrict base/max level for FBO completeness. |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 1); |
| + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test that a stale per-level image view is not reused after native storage is recreated via draw (syncState). |
| +TEST_P(Texture2DTestES3, StaleMipViewAfterDrawTriggeredStorageRecreation) |
| +{ |
| + ANGLE_GL_PROGRAM(program, getVertexShaderSource(), getFragmentShaderSource()); |
| + |
| + GLTexture tex; |
| + glBindTexture(GL_TEXTURE_2D, tex); |
| + |
| + // Create 256x256 base, generate mipmaps to create native storage. |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Resize base to 512x512. Retains stale views of old storage in levels 1-8. |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Recreate native storage via syncState (draw with texture bound). |
| + // Default MAX_LEVEL ensures full mip chain. NEAREST avoids mipmap completeness requirements. |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + drawQuad(program, "position", 0.0f); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Upload green to level 1. Must go to new native storage, not stale 128x128 view. |
| + std::vector<GLColor> greenPixels(256 * 256, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + greenPixels.data()); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Read back level 1 via FBO. |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 1); |
| + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test that mip data generated via generateMipmap survives a resize-up then resize-back sequence. |
| +TEST_P(Texture2DTestES3, MipDataPreservedAcrossResizeBack) |
| +{ |
| + GLTexture tex; |
| + glBindTexture(GL_TEXTURE_2D, tex); |
| + |
| + // Fill level 0 with green pixels and generate mipmaps. |
| + std::vector<GLColor> greenPixels(256 * 256, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + greenPixels.data()); |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Resize base to 512x512 (retains old mip views), then back to 256x256. |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Trigger ensureNativeStorageCreated via FBO attach so retained views get transferred. |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Level 1 (128x128) should contain the original green from generateMipmap. |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 1); |
| + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test that mip data survives a resize-up then resize-back sequence with a draw (syncState) between the resizes. |
| +TEST_P(Texture2DTestES3, MipDataPreservedAcrossResizeBackWithSyncState) |
| +{ |
| + ANGLE_GL_PROGRAM(program, getVertexShaderSource(), getFragmentShaderSource()); |
| + |
| + GLTexture tex; |
| + glBindTexture(GL_TEXTURE_2D, tex); |
| + |
| + // Fill level 0 with green pixels and generate mipmaps. |
| + std::vector<GLColor> greenPixels(256 * 256, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| + greenPixels.data()); |
| + glGenerateMipmap(GL_TEXTURE_2D); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Resize base to 512x512 (retains old mip views). |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Draw to trigger syncState -> ensureNativeStorageCreated for 512x512 storage. |
| + // Stale 128x128 views don't match the new 256x256 mip 1 — they survive in mTexImageDefs. |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + drawQuad(program, "position", 0.0f); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Resize back to 256x256. |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Trigger ensureNativeStorageCreated via FBO attach so retained views get transferred. |
| + GLFramebuffer fbo; |
| + glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); |
| + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Level 1 (128x128) should contain the original green from generateMipmap. |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); |
| + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 1); |
| + EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| + |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| // Checks that drawing incomplete zero texture buffer does not crash. |
| TEST_P(TextureBufferTestES31, DrawIncompleteZeroTexture) |
| { |
| diff --git a/src/tests/gl_tests/TransformFeedbackTest.cpp b/src/tests/gl_tests/TransformFeedbackTest.cpp |
| index 0174d8b2a5198069cfaae35ccc27e0ef538b4470..1c22af10342970f4b8afd092b5eaaeb19e1e8f1e 100644 |
| --- a/src/tests/gl_tests/TransformFeedbackTest.cpp |
| +++ b/src/tests/gl_tests/TransformFeedbackTest.cpp |
| @@ -11,7 +11,6 @@ |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| #include "util/EGLWindow.h" |
| -#include "util/gles_loader_autogen.h" |
| #include "util/random_utils.h" |
| #include "util/test_utils.h" |
| |
| @@ -5474,6 +5473,64 @@ TEST_P(TransformFeedbackTest, InstancedOverflowIncompletePrimitive) |
| EXPECT_EQ(6u, primitivesWritten); |
| } |
| |
| +// Test that UseProgram generates INVALID_OPERATION when transform feedback is active and not paused. |
| +TEST_P(TransformFeedbackTest, UseProgramWhileActiveAndNotPaused) |
| +{ |
| + std::vector<std::string> tfVaryings = {"gl_Position"}; |
| + compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS); |
| + ANGLE_GL_PROGRAM(otherProgram, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red()); |
| + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer); |
| + glUseProgram(mProgram); |
| + glBeginTransformFeedback(GL_POINTS); |
| + ASSERT_GL_NO_ERROR(); |
| + glUseProgram(otherProgram); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + GLint currentProgram = 0; |
| + glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); |
| + EXPECT_EQ(static_cast<GLuint>(currentProgram), mProgram); |
| + glEndTransformFeedback(); |
| + EXPECT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test that LinkProgram generates INVALID_OPERATION when the program is used by an active |
| +// transform feedback object, even if it is paused. |
| +TEST_P(TransformFeedbackTest, LinkProgramWhileActiveAndPaused) |
| +{ |
| + std::vector<std::string> tfVaryings = {"gl_Position"}; |
| + compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS); |
| + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer); |
| + glUseProgram(mProgram); |
| + glBeginTransformFeedback(GL_POINTS); |
| + glPauseTransformFeedback(); |
| + ASSERT_GL_NO_ERROR(); |
| + glLinkProgram(mProgram); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + glEndTransformFeedback(); |
| + EXPECT_GL_NO_ERROR(); |
| +} |
| + |
| +// Test that BindBufferBase, BindBufferRange with TRANSFORM_FEEDBACK_BUFFER generates INVALID_OPERATION when |
| +// transform feedback is active. |
| +TEST_P(TransformFeedbackTest, BindBufferBaseWhileActive) |
| +{ |
| + std::vector<std::string> tfVaryings = {"gl_Position"}; |
| + compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS); |
| + |
| + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer); |
| + glUseProgram(mProgram); |
| + glBeginTransformFeedback(GL_POINTS); |
| + ASSERT_GL_NO_ERROR(); |
| + GLBuffer otherBuffer; |
| + glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, otherBuffer); |
| + glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1024, nullptr, GL_STATIC_DRAW); |
| + glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, otherBuffer); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, otherBuffer, 0, 512); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + glEndTransformFeedback(); |
| + EXPECT_GL_NO_ERROR(); |
| +} |
| + |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TransformFeedbackTest); |
| ANGLE_INSTANTIATE_TEST_ES3_AND_ES31_AND_ES32_AND( |
| TransformFeedbackTest, |
| diff --git a/src/tests/gl_tests/UniformTest.cpp b/src/tests/gl_tests/UniformTest.cpp |
| index fc742ddb4b03d07e6ebbd513360cd8118b245a07..5afd3663fb967b1f364d3ab353a05b0a1bda5586 100644 |
| --- a/src/tests/gl_tests/UniformTest.cpp |
| +++ b/src/tests/gl_tests/UniformTest.cpp |
| @@ -13,7 +13,6 @@ |
| #include "test_utils/angle_test_configs.h" |
| #include "test_utils/angle_test_instantiate.h" |
| #include "test_utils/gl_raii.h" |
| -#include "util/gles_loader_autogen.h" |
| #include "util/shader_utils.h" |
| |
| #include <array> |
| @@ -3444,7 +3443,7 @@ TEST_P(UniformTestES3, MatrixUniformUpload) |
| matrixValues[i] = static_cast<GLfloat>(i); |
| } |
| |
| - using UniformMatrixCxRfv = decltype(glUniformMatrix2fv); |
| + using UniformMatrixCxRfv = GL_APIENTRY void (*)(GLint, GLsizei, GLboolean, const GLfloat *); |
| UniformMatrixCxRfv uniformMatrixCxRfv[kMaxDims + 1][kMaxDims + 1] = { |
| {nullptr, nullptr, nullptr, nullptr, nullptr}, |
| {nullptr, nullptr, nullptr, nullptr, nullptr}, |
| diff --git a/src/tests/gl_tests/VertexAttributeTest.cpp b/src/tests/gl_tests/VertexAttributeTest.cpp |
| index adf419e46baff146b95e5364f7059294e6be9609..84e1787c6aaee4d8590681bb46ece8c2d74c67ee 100644 |
| --- a/src/tests/gl_tests/VertexAttributeTest.cpp |
| +++ b/src/tests/gl_tests/VertexAttributeTest.cpp |
| @@ -5792,6 +5792,212 @@ void main(void) |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, expected, 1); |
| } |
| |
| +// Verify that a near-max-size buffer with stride=1 completes without crashing |
| +// due to threadgroup rounding overflow. The fix adjusts threadgroup width to prevent overflow. |
| +// Note: We only verify no GL error occurs; pixel verification with a 4GB buffer is impractical. |
| +TEST_P(VertexAttributeTestES3, MaxSizeBufferWithByteConversionDoesNotCrash) |
| +{ |
| + constexpr char kVS[] = R"(#version 300 es |
| +in vec4 position; |
| +void main() |
| +{ |
| + gl_Position = position; |
| +})"; |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp float; |
| +out vec4 fragColor; |
| +void main() |
| +{ |
| + fragColor = vec4(0.0, 1.0, 0.0, 1.0); |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, kVS, kFS); |
| + glUseProgram(program); |
| + |
| + GLint positionLocation = glGetAttribLocation(program, "position"); |
| + ASSERT_NE(-1, positionLocation); |
| + |
| + // Create a near-max-size buffer to trigger the overflow-prone code path |
| + const GLuint maxSize = 0xFFFFFFFC; // Near UINT32_MAX, aligned to 4 bytes |
| + GLBuffer buffer; |
| + glBindBuffer(GL_ARRAY_BUFFER, buffer); |
| + glBufferData(GL_ARRAY_BUFFER, maxSize, nullptr, GL_STATIC_DRAW); |
| + ANGLE_SKIP_TEST_IF(glGetError() == GL_OUT_OF_MEMORY); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + // Use stride=1 with GL_BYTE to trigger vertex format conversion compute path |
| + glEnableVertexAttribArray(positionLocation); |
| + glVertexAttribPointer(positionLocation, 4, GL_BYTE, GL_FALSE, 1, nullptr); |
| + |
| + // Draw a minimal number of vertices - this should not crash or produce an error |
| + glDrawArrays(GL_TRIANGLES, 0, 3); |
| + |
| + // The key verification: no crash occurred and no GL error was generated |
| + ASSERT_GL_NO_ERROR(); |
| +} |
| + |
| +// Verify GL_BYTE with stride=4 triggers format conversion and renders correctly. |
| +TEST_P(VertexAttributeTestES3, ByteConversionWithSmallStrideRendersCorrectly) |
| +{ |
| + constexpr char kVS[] = R"(#version 300 es |
| +in vec4 position; |
| +in vec4 testAttrib; |
| +out vec4 color; |
| +void main() |
| +{ |
| + gl_Position = position; |
| + color = testAttrib / 127.0; |
| +})"; |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp float; |
| +in vec4 color; |
| +out vec4 fragColor; |
| +void main() |
| +{ |
| + fragColor = color; |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, kVS, kFS); |
| + glUseProgram(program); |
| + |
| + GLint positionLocation = glGetAttribLocation(program, "position"); |
| + GLint testAttribLocation = glGetAttribLocation(program, "testAttrib"); |
| + ASSERT_NE(-1, positionLocation); |
| + ASSERT_NE(-1, testAttribLocation); |
| + |
| + GLBuffer quadBuffer; |
| + InitQuadVertexBuffer(&quadBuffer); |
| + glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| + glEnableVertexAttribArray(positionLocation); |
| + |
| + // All vertices read [127, 127, 127, 127] → 127/127 = 1.0 → white |
| + std::array<GLbyte, 24> testData; |
| + testData.fill(127); |
| + |
| + GLBuffer testBuffer; |
| + glBindBuffer(GL_ARRAY_BUFFER, testBuffer); |
| + glBufferData(GL_ARRAY_BUFFER, testData.size(), testData.data(), GL_STATIC_DRAW); |
| + glVertexAttribPointer(testAttribLocation, 4, GL_BYTE, GL_FALSE, 4, nullptr); |
| + glEnableVertexAttribArray(testAttribLocation); |
| + |
| + glClearColor(0, 0, 0, 0); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + drawQuad(program, "position", 0.5f); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + EXPECT_PIXEL_COLOR_NEAR(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::white, 1); |
| +} |
| + |
| +// Verify GL_BYTE with stride=1 (< format size) triggers conversion and renders correctly. |
| +TEST_P(VertexAttributeTestES3, ByteConversionSmallBufferRendersCorrectly) |
| +{ |
| + constexpr char kVS[] = R"(#version 300 es |
| +in vec4 position; |
| +in vec4 testAttrib; |
| +flat out vec4 color; |
| +void main() |
| +{ |
| + gl_Position = position; |
| + // Normalize signed byte: max GLbyte (127) maps to 1.0. |
| + // All components at 1.0 produce white, which is easy to verify with EXPECT_PIXEL_COLOR. |
| + color = testAttrib / 127.0; |
| +})"; |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision highp float; |
| +flat in vec4 color; |
| +out vec4 fragColor; |
| +void main() |
| +{ |
| + fragColor = color; |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, kVS, kFS); |
| + glUseProgram(program); |
| + |
| + GLint positionLocation = glGetAttribLocation(program, "position"); |
| + GLint testAttribLocation = glGetAttribLocation(program, "testAttrib"); |
| + ASSERT_NE(-1, positionLocation); |
| + ASSERT_NE(-1, testAttribLocation); |
| + |
| + GLBuffer quadBuffer; |
| + InitQuadVertexBuffer(&quadBuffer); |
| + glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr); |
| + glEnableVertexAttribArray(positionLocation); |
| + |
| + // Uniform data so overlapping stride=1 reads all get [127, 127, 127, 127] → white |
| + std::array<GLbyte, 32> testData; |
| + testData.fill(127); |
| + |
| + GLBuffer testBuffer; |
| + glBindBuffer(GL_ARRAY_BUFFER, testBuffer); |
| + glBufferData(GL_ARRAY_BUFFER, testData.size(), testData.data(), GL_STATIC_DRAW); |
| + glVertexAttribPointer(testAttribLocation, 4, GL_BYTE, GL_FALSE, 1, nullptr); |
| + glEnableVertexAttribArray(testAttribLocation); |
| + |
| + glClearColor(0, 0, 0, 0); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + drawQuad(program, "position", 0.5f); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor::white, 1); |
| +} |
| + |
| +// After a draw with an out-of-bounds vertex attribute offset (undefined behavior in ES), |
| +// verify that subsequent valid draws still render correctly and the backend state is not |
| +// corrupted. |
| +TEST_P(VertexAttributeTest, OutOfBoundsOffsetNoFormatConversion) |
| +{ |
| + constexpr char kVS[] = |
| + R"(attribute vec4 a_position; |
| +void main() |
| +{ |
| + gl_Position = a_position; |
| + gl_PointSize = 1.0; |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red()); |
| + glUseProgram(program); |
| + |
| + GLint posLoc = glGetAttribLocation(program, "a_position"); |
| + ASSERT_NE(-1, posLoc); |
| + |
| + const GLfloat vertices[] = { |
| + -1.0f, -1.0f, |
| + 1.0f, -1.0f, |
| + 1.0f, 1.0f, |
| + -1.0f, 1.0f, |
| + }; |
| + GLBuffer buffer; |
| + glBindBuffer(GL_ARRAY_BUFFER, buffer); |
| + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
| + |
| + glEnableVertexAttribArray(posLoc); |
| + |
| + // Valid draw: prove setup is correct. |
| + glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
| + ASSERT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(32, 32, GLColor::red); |
| + |
| + // OOB draw: offset far exceeds buffer. Result is UB in ES — no assertion. |
| + glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, |
| + reinterpret_cast<const void *>(1024)); |
| + glDrawArrays(GL_POINTS, 0, 1); |
| + |
| + // Valid draw again: prove the backend recovered and state is not corrupted. |
| + glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); |
| + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| + glClear(GL_COLOR_BUFFER_BIT); |
| + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
| + ASSERT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(32, 32, GLColor::red); |
| +} |
| + |
| // VAO emulation fails on Mac but is not used on Mac in the wild. http://anglebug.com/40096758 |
| #if !defined(__APPLE__) |
| # define EMULATED_VAO_CONFIGS \ |
| @@ -6347,7 +6553,8 @@ TEST_P(VertexAttributeUint8Test, ConvertUint8IndexAtEndOfBuffer) |
| std::vector<float> verts(256 * 2); |
| for (int i = 0; i < 256; i++) |
| { |
| - float x, y; |
| + float x = 0; |
| + float y = 0; |
| // Vertices 0, 1, 2: cover the right half of the framebuffer |
| // Vertices 3, 4, 5: cover the left half of the framebuffer |
| switch (i % 6) |
| diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp |
| index ad86bb08464cfd69fac3e87eec06eb8864e21f11..1429af27bcfa0ab47efb963c83f0158f4df4fd48 100644 |
| --- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp |
| +++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp |
| @@ -1759,13 +1759,16 @@ void main() |
| ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red()); |
| glUseProgram(program); |
| |
| + GLint posLocation = glGetAttribLocation(program, "a_Position"); |
| + ASSERT_NE(-1, posLocation); |
| + glEnableVertexAttribArray(posLocation); |
| constexpr float kVertexData[] = { |
| 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, |
| }; |
| - |
| GLBuffer vertexBuffer; |
| glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STREAM_DRAW); |
| + glVertexAttribPointer(posLocation, 4, GL_FLOAT, GL_FALSE, 0, nullptr); |
| |
| GLuint positionLocation = glGetAttribLocation(program, "a_Position"); |
| glEnableVertexAttribArray(positionLocation); |
| @@ -1793,6 +1796,33 @@ void main() |
| // Neither index is representable as 32-bit int |
| glDrawElements(GL_POINTS, 4, GL_UNSIGNED_INT, reinterpret_cast<void *>(sizeof(GLuint) * 2)); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + |
| + constexpr GLuint kIndexData2[] = { |
| + 0, |
| + std::numeric_limits<GLuint>::max(), |
| + }; |
| + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndexData2), kIndexData2, GL_DYNAMIC_DRAW); |
| + |
| + glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, 0); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + |
| + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, reinterpret_cast<void *>(2)); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + |
| + glDrawElements(GL_LINES, 2, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(3)); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + |
| + constexpr GLuint kIndexData3[] = {0, 1}; |
| + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndexData3), kIndexData3, GL_DYNAMIC_DRAW); |
| + |
| + glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, 0); |
| + EXPECT_GL_NO_ERROR(); |
| + |
| + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, reinterpret_cast<void *>(2)); |
| + EXPECT_GL_NO_ERROR(); |
| + |
| + glDrawElements(GL_LINES, 2, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(3)); |
| + EXPECT_GL_NO_ERROR(); |
| } |
| |
| // Test for drawing with a null index buffer |
| @@ -3515,6 +3545,49 @@ TEST_P(WebGLCompatibilityTest, CompressedTexImageBPTC) |
| } |
| } |
| |
| +// Sampling an uninitialized COMPRESSED_RGBA_ASTC_4x4_KHR texture allocated via glTexStorage2D |
| +// should yield NaN per the ASTC spec for empty/undefined block data; the NaN-to-magenta shader |
| +// should therefore produce magenta. Isolates the first failing sub-test of the WebGL conformance |
| +// test webgl/2.0.y/conformance/extensions/webgl-compressed-texture-astc.html on Metal. |
| +TEST_P(WebGL2CompatibilityTest, CompressedTextureASTCEmptyStorageError) |
| +{ |
| + ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_KHR_texture_compression_astc_ldr")); |
| + |
| + constexpr char kFS[] = R"(#version 300 es |
| +precision mediump float; |
| +uniform sampler2D u_tex2D; |
| +in vec2 v_texCoord; |
| +out vec4 out_color; |
| +void main() |
| +{ |
| + vec4 c = texture(u_tex2D, v_texCoord); |
| + if (all(isnan(c))) |
| + out_color = vec4(1, 0, 1, 1); |
| + else |
| + out_color = c; |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Texture2DLod(), kFS); |
| + glUseProgram(program); |
| + glUniform1i(glGetUniformLocation(program, essl3_shaders::Texture2DUniform()), 0); |
| + |
| + GLTexture texture; |
| + glBindTexture(GL_TEXTURE_2D, texture); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + |
| + glTexStorage2D(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGBA_ASTC_4x4_KHR, 16, 16); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + glViewport(0, 0, getWindowWidth(), getWindowHeight()); |
| + drawQuad(program, essl3_shaders::PositionAttrib(), 0.0f, 1.0f, /*useVertexBuffer=*/true); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta); |
| +} |
| + |
| TEST_P(WebGLCompatibilityTest, L32FTextures) |
| { |
| constexpr float textureData[] = {15.1f, 0.0f, 0.0f, 0.0f}; |
| @@ -8256,6 +8329,147 @@ void main() |
| } |
| } |
| |
| +// Create an integer format texture but specify a FLOAT sampler. In WebGL, |
| +// unlike OpenGL, this must generate INVALID_OPERATION at draw time. |
| +// Also verify that with a matching float texture, the draw succeeds and |
| +// produces the expected output. |
| +// Modeled after TEST_P(Texture2DTestES3, TexImageFormatMismatch). |
| +TEST_P(WebGL2CompatibilityTest, TexImageFormatMismatch) |
| +{ |
| + constexpr char kVS[] = |
| + R"(#version 300 es |
| +in vec4 a_position; |
| +out vec2 v_texCoord; |
| +void main() |
| +{ |
| + gl_Position = a_position; |
| + v_texCoord = (a_position.xy * 0.5) + 0.5; |
| +})"; |
| + |
| + constexpr char kFS[] = |
| + R"(#version 300 es |
| +precision highp float; |
| +uniform highp sampler2D tex; |
| +in vec2 v_texCoord; |
| +out vec4 fragColor; |
| +void main() |
| +{ |
| + fragColor = texture(tex, v_texCoord); |
| +})"; |
| + |
| + ANGLE_GL_PROGRAM(program, kVS, kFS); |
| + |
| + GLint texLocation = glGetUniformLocation(program, "tex"); |
| + ASSERT_NE(-1, texLocation); |
| + |
| + glUseProgram(program); |
| + |
| + glUniform1i(texLocation, 0); |
| + |
| + // First, verify that a matching float-format texture works and draws correctly. |
| + GLTexture tex; |
| + glBindTexture(GL_TEXTURE_2D, tex); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + |
| + std::vector<GLColor> greenData(8 * 8, GLColor::green); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, greenData.data()); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + glActiveTexture(GL_TEXTURE0); |
| + glBindTexture(GL_TEXTURE_2D, tex); |
| + |
| + // Drawing with a matching sampler/texture format must succeed. |
| + drawQuad(program, "a_position", 0.5f, 1.0f, true); |
| + ASSERT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| + |
| + // In WebGL, drawing with a sampler/texture format mismatch must fail. |
| + GLubyte texData[8 * 8 * 2] = {}; |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 8, 8, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, texData); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + drawQuad(program, "a_position", 0.5f, 1.0f, true); |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| +} |
| + |
| +// Test that drawing a large GLuint index works. |
| +TEST_P(WebGL2CompatibilityTest, DrawLargeIndex) |
| +{ |
| + constexpr std::array<GLfloat, 4> kGreen = {0.0f, 1.0f, 0.0f, 1.0f}; |
| + constexpr GLuint offset = 0x80000000; |
| + GLuint indexData[] = {0, 1, 2, 1, 3, 2}; |
| + for (auto& index : indexData) |
| + { |
| + index += offset; |
| + } |
| + float vertexData[] = {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f}; |
| + |
| + GLBuffer indexBuffer; |
| + ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| + GLint vPos = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| + ASSERT_NE(vPos, -1); |
| + glUseProgram(program); |
| + GLint colorUniformLocation = |
| + glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); |
| + ASSERT_NE(colorUniformLocation, -1); |
| + |
| + GLBuffer vertexBuffer; |
| + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| + glBufferData(GL_ARRAY_BUFFER, offset * sizeof(float) * 2 + sizeof(vertexData), nullptr, GL_STATIC_DRAW); |
| + glBufferSubData(GL_ARRAY_BUFFER, offset * sizeof(float) * 2, sizeof(vertexData), vertexData); |
| + glVertexAttribPointer(vPos, 2, GL_FLOAT, GL_FALSE, 0, nullptr); |
| + glEnableVertexAttribArray(vPos); |
| + |
| + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); |
| + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_DYNAMIC_DRAW); |
| + |
| + glUniform4fv(colorUniformLocation, 1, kGreen.data()); |
| + ASSERT_GL_NO_ERROR(); |
| + |
| + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); |
| + ASSERT_GL_NO_ERROR(); |
| + EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, 0, GLColor::green); |
| + EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() - 1, GLColor::green); |
| +} |
| + |
| +// Test that drawing a large GLuint index is detected as out-of-bounds access. |
| +TEST_P(WebGL2CompatibilityTest, DrawLargeIndexOOB) |
| +{ |
| + constexpr GLuint offset = 0x80000000; |
| + GLuint indexData[] = {0, 1, 2}; |
| + for (auto& index : indexData) |
| + { |
| + index += offset; |
| + } |
| + GLBuffer indexBuffer; |
| + ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); |
| + GLint vPos = glGetAttribLocation(program, essl1_shaders::PositionAttrib()); |
| + ASSERT_NE(vPos, -1); |
| + glUseProgram(program); |
| + |
| + GLBuffer vertexBuffer; |
| + glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); |
| + glBufferData(GL_ARRAY_BUFFER, 10, nullptr, GL_STATIC_DRAW); |
| + glVertexAttribPointer(vPos, 2, GL_FLOAT, GL_FALSE, 0, nullptr); |
| + glEnableVertexAttribArray(vPos); |
| + |
| + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); |
| + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData), indexData, GL_DYNAMIC_DRAW); |
| + |
| + EXPECT_GL_NO_ERROR(); |
| + glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, nullptr); |
| + if (!IsGLExtensionEnabled("GL_KHR_robust_buffer_access_behavior")) |
| + { |
| + EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| + } |
| + else |
| + { |
| + EXPECT_GL_NO_ERROR(); |
| + } |
| +} |
| + |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest); |
| |
| ANGLE_INSTANTIATE_TEST_ES2(WebGL1CompatibilityTest); |
| diff --git a/src/tests/perf_tests/ANGLEPerfTest.cpp b/src/tests/perf_tests/ANGLEPerfTest.cpp |
| index ba4b1d88229c0d2b1b1c6860b186f3d1c6bafc54..3d21dafb34a9372474c47f5ad7dceb07e0fea342 100644 |
| --- a/src/tests/perf_tests/ANGLEPerfTest.cpp |
| +++ b/src/tests/perf_tests/ANGLEPerfTest.cpp |
| @@ -760,9 +760,9 @@ void ANGLEPerfTest::atraceCounter(const char *counterName, int64_t counterValue) |
| RenderTestParams::RenderTestParams() |
| { |
| #if defined(ANGLE_DEBUG_LAYERS_ENABLED) |
| - eglParameters.debugLayersEnabled = true; |
| + eglParameters.debugLayersEnabled = EGL_TRUE; |
| #else |
| - eglParameters.debugLayersEnabled = false; |
| + eglParameters.debugLayersEnabled = EGL_FALSE; |
| #endif |
| } |
| |
| diff --git a/src/tests/test_expectations/GPUTestConfig.cpp b/src/tests/test_expectations/GPUTestConfig.cpp |
| index c5df9c002e56064d51ae2c00af4c8b6e88f15304..8c84d98cbbf39a3a0f31beae2dc35336fe4e1dba 100644 |
| --- a/src/tests/test_expectations/GPUTestConfig.cpp |
| +++ b/src/tests/test_expectations/GPUTestConfig.cpp |
| @@ -13,6 +13,7 @@ |
| #include "common/debug.h" |
| #include "common/platform_helpers.h" |
| #include "common/string_utils.h" |
| +#include "common/system_utils.h" |
| #include "gpu_info_util/SystemInfo.h" |
| |
| #if defined(ANGLE_PLATFORM_APPLE) |
| @@ -527,6 +528,7 @@ GPUTestConfig::GPUTestConfig(bool isSwiftShader) |
| mConditions[kConditionMacMojave] = IsMacMojave(); |
| mConditions[kConditionMac] = IsMac(); |
| mConditions[kConditionIOS] = IsIOS(); |
| + mConditions[kConditionIOSSimulator] = IsIOSSimulator(); |
| mConditions[kConditionLinux] = IsLinux(); |
| mConditions[kConditionAndroid] = IsAndroid(); |
| // HW vendors are irrelevant if we are running on SW |
| @@ -542,6 +544,11 @@ GPUTestConfig::GPUTestConfig(bool isSwiftShader) |
| |
| mConditions[kConditionRelease] = IsRelease(); |
| mConditions[kConditionDebug] = IsDebug(); |
| +#if defined(ANGLE_PLATFORM_APPLE) |
| + mConditions[kConditionDebugLayers] = GetEnvironmentVar("MTL_DEBUG_LAYER") == "1"; |
| +#else |
| + mConditions[kConditionDebugLayers] = false; |
| +#endif |
| // If no API provided, pass these conditions by default |
| mConditions[kConditionD3D9] = true; |
| mConditions[kConditionD3D11] = true; |
| diff --git a/src/tests/test_expectations/GPUTestConfig.h b/src/tests/test_expectations/GPUTestConfig.h |
| index a72d9b6e3d2075b0495bcc6061c236fb48f45906..5a52b77d3aeb33120db582638750b47ae79e1b99 100644 |
| --- a/src/tests/test_expectations/GPUTestConfig.h |
| +++ b/src/tests/test_expectations/GPUTestConfig.h |
| @@ -50,6 +50,7 @@ struct GPUTestConfig |
| kConditionMacMojave, |
| kConditionMac, |
| kConditionIOS, |
| + kConditionIOSSimulator, |
| kConditionLinux, |
| kConditionAndroid, |
| kConditionNVIDIA, |
| @@ -62,6 +63,7 @@ struct GPUTestConfig |
| kConditionSamsung, |
| kConditionRelease, |
| kConditionDebug, |
| + kConditionDebugLayers, |
| kConditionD3D9, |
| kConditionD3D11, |
| kConditionGLDesktop, |
| diff --git a/src/tests/test_expectations/GPUTestExpectationsParser.cpp b/src/tests/test_expectations/GPUTestExpectationsParser.cpp |
| index 3cffe1beba0d28d18c4844577db33573179f3f35..97f2165d635230fd49921243dd0f8107160bee88 100644 |
| --- a/src/tests/test_expectations/GPUTestExpectationsParser.cpp |
| +++ b/src/tests/test_expectations/GPUTestExpectationsParser.cpp |
| @@ -53,6 +53,7 @@ enum Token |
| kConfigMacMojave, |
| kConfigMac, |
| kConfigIOS, |
| + kConfigIOSSimulator, |
| kConfigLinux, |
| kConfigChromeOS, |
| kConfigAndroid, |
| @@ -68,6 +69,7 @@ enum Token |
| // build type |
| kConfigRelease, |
| kConfigDebug, |
| + kConfigDebugLayers, |
| // ANGLE renderer |
| kConfigD3D9, |
| kConfigD3D11, |
| @@ -184,6 +186,7 @@ constexpr TokenInfo kTokenData[kNumberOfTokens] = { |
| {"mojave", GPUTestConfig::kConditionMacMojave}, |
| {"mac", GPUTestConfig::kConditionMac}, |
| {"ios", GPUTestConfig::kConditionIOS}, |
| + {"iossimulator", GPUTestConfig::kConditionIOSSimulator}, |
| {"linux", GPUTestConfig::kConditionLinux}, |
| {"chromeos", |
| GPUTestConfig::kConditionNone}, // https://anglebug.com/42262032 CrOS not supported |
| @@ -198,6 +201,7 @@ constexpr TokenInfo kTokenData[kNumberOfTokens] = { |
| {"samsung", GPUTestConfig::kConditionSamsung}, |
| {"release", GPUTestConfig::kConditionRelease}, |
| {"debug", GPUTestConfig::kConditionDebug}, |
| + {"debuglayers", GPUTestConfig::kConditionDebugLayers}, |
| {"d3d9", GPUTestConfig::kConditionD3D9}, |
| {"d3d11", GPUTestConfig::kConditionD3D11}, |
| {"opengl", GPUTestConfig::kConditionGLDesktop}, |
| @@ -526,6 +530,7 @@ bool GPUTestExpectationsParser::parseLine(const GPUTestConfig *config, |
| case kConfigMacMojave: |
| case kConfigMac: |
| case kConfigIOS: |
| + case kConfigIOSSimulator: |
| case kConfigLinux: |
| case kConfigChromeOS: |
| case kConfigAndroid: |
| @@ -539,6 +544,7 @@ bool GPUTestExpectationsParser::parseLine(const GPUTestConfig *config, |
| case kConfigSamsung: |
| case kConfigRelease: |
| case kConfigDebug: |
| + case kConfigDebugLayers: |
| case kConfigD3D9: |
| case kConfigD3D11: |
| case kConfigGLDesktop: |
| diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp |
| index 8f82d882785ef6b1dcd55de50c7c369df0a5a5a1..4bfd9b5658d83fddd357ec1a0e1d8b9192764b52 100644 |
| --- a/src/tests/test_utils/ANGLETest.cpp |
| +++ b/src/tests/test_utils/ANGLETest.cpp |
| @@ -26,9 +26,7 @@ |
| # include <VersionHelpers.h> |
| #endif // defined(ANGLE_PLATFORM_WINDOWS) |
| |
| -#if defined(ANGLE_HAS_RAPIDJSON) |
| -# include "test_utils/runner/TestSuite.h" |
| -#endif // defined(ANGLE_HAS_RAPIDJSON) |
| +#include "test_utils/runner/TestSuite.h" |
| |
| namespace angle |
| { |
| @@ -170,6 +168,8 @@ const char *GetColorName(GLColorRGB color) |
| // Always re-use displays when using --bot-mode in the test runner. |
| bool gReuseDisplays = false; |
| |
| +bool gAlwaysShowWindow = false; |
| + |
| bool ShouldAlwaysForceNewDisplay(const PlatformParameters ¶ms) |
| { |
| // When running WebGPU tests always force a new display. |
| @@ -453,6 +453,8 @@ constexpr char kBatchId[] = "--batch-id="; |
| constexpr char kDelayTestStart[] = "--delay-test-start="; |
| constexpr char kRenderDoc[] = "--renderdoc"; |
| constexpr char kNoRenderDoc[] = "--no-renderdoc"; |
| +constexpr char kDisableDebugLayers[] = "--disable-debug-layers"; |
| +constexpr char kAlwaysShowWindow[] = "--always-show-window"; |
| |
| void SetupEnvironmentVarsForCaptureReplay() |
| { |
| @@ -551,11 +553,19 @@ ANGLETestBase::ANGLETestBase(const PlatformParameters ¶ms) |
| if (withMethods.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) |
| { |
| #if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS) |
| - withMethods.eglParameters.debugLayersEnabled = true; |
| + withMethods.eglParameters.debugLayersEnabled = EGL_TRUE; |
| #else |
| - withMethods.eglParameters.debugLayersEnabled = false; |
| + withMethods.eglParameters.debugLayersEnabled = EGL_FALSE; |
| #endif |
| } |
| + else |
| + { |
| + if (withMethods.eglParameters.debugLayersEnabled == EGL_DONT_CARE) |
| + { |
| + withMethods.eglParameters.debugLayersEnabled = |
| + gDisableDebugLayers ? EGL_FALSE : EGL_TRUE; |
| + } |
| + } |
| |
| if (gEnableRenderDocCapture) |
| { |
| @@ -623,8 +633,7 @@ void ANGLETestBase::initOSWindow() |
| return; |
| } |
| |
| - // On Linux we must keep the test windows visible. On Windows it doesn't seem to need it. |
| - setWindowVisible(getOSWindow(), !IsWindows()); |
| + setWindowVisible(getOSWindow(), shouldShowWindow()); |
| |
| switch (mCurrentParams->driver) |
| { |
| @@ -712,9 +721,6 @@ void ANGLETestBase::ANGLETestSetUp() |
| fullTestNameStr << testInfo->test_suite_name() << "." << testInfo->name(); |
| std::string fullTestName = fullTestNameStr.str(); |
| |
| - // TODO(b/279980674): TestSuite depends on rapidjson which we don't have in aosp builds, |
| - // for now disable both TestSuite and expectations. |
| -#if defined(ANGLE_HAS_RAPIDJSON) |
| TestSuite *testSuite = TestSuite::GetInstance(); |
| int32_t testExpectation = |
| testSuite->getTestExpectationWithConfigAndUpdateTimeout(testConfig, fullTestName); |
| @@ -723,7 +729,6 @@ void ANGLETestBase::ANGLETestSetUp() |
| { |
| GTEST_SKIP() << "Test skipped on this config"; |
| } |
| -#endif |
| |
| if (IsWindows()) |
| { |
| @@ -1725,6 +1730,13 @@ int ANGLETestBase::getClientMajorVersion() const |
| return getGLWindow()->getClientMajorVersion(); |
| } |
| |
| +bool ANGLETestBase::shouldShowWindow() const |
| +{ |
| + // On Linux we must keep the test windows visible. On Windows or Metal it doesn't seem to need |
| + // it. |
| + return gAlwaysShowWindow || !(IsWindows() || IsMac() || IsIOS()); |
| +} |
| + |
| int ANGLETestBase::getClientMinorVersion() const |
| { |
| return getGLWindow()->getClientMinorVersion(); |
| @@ -1921,5 +1933,13 @@ void ANGLEProcessTestArgs(int *argc, char *argv[]) |
| { |
| gEnableRenderDocCapture = false; |
| } |
| + else if (strncmp(argv[argIndex], kDisableDebugLayers, strlen(kDisableDebugLayers)) == 0) |
| + { |
| + gDisableDebugLayers = true; |
| + } |
| + else if (strncmp(argv[argIndex], kAlwaysShowWindow, strlen(kAlwaysShowWindow)) == 0) |
| + { |
| + gAlwaysShowWindow = true; |
| + } |
| } |
| } |
| diff --git a/src/tests/test_utils/ANGLETest.h b/src/tests/test_utils/ANGLETest.h |
| index 200b6677af6b830b18c4567d7d158f36c510ac89..ec4cd5567fb4dbd662cb573a86f028511354a883 100644 |
| --- a/src/tests/test_utils/ANGLETest.h |
| +++ b/src/tests/test_utils/ANGLETest.h |
| @@ -596,6 +596,8 @@ class ANGLETestBase : public ::testing::Test |
| return mCurrentParams->getRenderer() == EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE; |
| } |
| |
| + bool shouldShowWindow() const; |
| + |
| bool isDriverSystemEgl() const |
| { |
| return mCurrentParams->driver == angle::GLESDriverType::SystemEGL; |
| diff --git a/src/tests/test_utils/ANGLETestCL.cpp b/src/tests/test_utils/ANGLETestCL.cpp |
| index 03e9037aaca4df6de668fac7ed2819b76dc2d936..28b076380cc304c6fd52af0ad0d23c95cfe3b52c 100644 |
| --- a/src/tests/test_utils/ANGLETestCL.cpp |
| +++ b/src/tests/test_utils/ANGLETestCL.cpp |
| @@ -41,9 +41,9 @@ ANGLETestCL<PlatformParameters>::ANGLETestCL(const PlatformParameters ¶ms) |
| if (mCurrentParams.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) |
| { |
| #if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS) |
| - mCurrentParams.eglParameters.debugLayersEnabled = true; |
| + mCurrentParams.eglParameters.debugLayersEnabled = EGL_TRUE; |
| #else |
| - mCurrentParams.eglParameters.debugLayersEnabled = false; |
| + mCurrentParams.eglParameters.debugLayersEnabled = EGL_FALSE; |
| #endif |
| } |
| |
| diff --git a/src/tests/test_utils/angle_test_instantiate.cpp b/src/tests/test_utils/angle_test_instantiate.cpp |
| index 05a5d1c077336e36bb1d6adeb641cedfa398bf48..88246940a036bdb7a1e5f182aca418335876676c 100644 |
| --- a/src/tests/test_utils/angle_test_instantiate.cpp |
| +++ b/src/tests/test_utils/angle_test_instantiate.cpp |
| @@ -194,6 +194,8 @@ bool gEnableRenderDocCapture = true; |
| bool gEnableRenderDocCapture = false; |
| #endif |
| |
| +bool gDisableDebugLayers = false; |
| + |
| bool IsConfigSelected() |
| { |
| return gSelectedConfig[0] != 0; |
| diff --git a/src/tests/test_utils/angle_test_instantiate.h b/src/tests/test_utils/angle_test_instantiate.h |
| index 73d8128344e87cd49095f4dddae43a7814bd1df2..ff55cfb0cc99216be3f577fdb02e7c8998271224 100644 |
| --- a/src/tests/test_utils/angle_test_instantiate.h |
| +++ b/src/tests/test_utils/angle_test_instantiate.h |
| @@ -388,6 +388,8 @@ extern bool gEnableANGLEPerTestCaptureLabel; |
| |
| extern bool gEnableRenderDocCapture; |
| |
| +extern bool gDisableDebugLayers; |
| + |
| // For use with ANGLE_INSTANTIATE_TEST_ARRAY |
| template <typename ParamsT> |
| using ModifierFunc = std::function<ParamsT(const ParamsT &)>; |
| diff --git a/src/tests/test_utils/runner/README.md b/src/tests/test_utils/runner/README.md |
| index 739d3f6c2c00c080b8901e5c83cb2cf761ec2a61..25dbbcd7857e64756152beae90220646bf8a7256 100644 |
| --- a/src/tests/test_utils/runner/README.md |
| +++ b/src/tests/test_utils/runner/README.md |
| @@ -28,6 +28,7 @@ following additional command-line arguments: |
| * `--disable-crash-handler` forces off OS-level crash handling |
| * `--isolated-outdir` specifies a test artifacts directory |
| * `--max-failures` specifies a count of failures after which the harness early exits. |
| + * `--disable-debug-layers` disables debug layers for GPU drivers, if they were used by default. |
| |
| `--isolated-script-test-output` and `--isolated-script-perf-test-output` mirror `--results-file` |
| and `--histogram-json-file` respectively. |
| diff --git a/src/tests/test_utils/runner/TestSuite.cpp b/src/tests/test_utils/runner/TestSuite.cpp |
| index cd3cb3b31c793613b7b7035d093206ad755e173b..9e6a90300ed505c525fe40e4c0102627a9a0a045 100644 |
| --- a/src/tests/test_utils/runner/TestSuite.cpp |
| +++ b/src/tests/test_utils/runner/TestSuite.cpp |
| @@ -25,16 +25,20 @@ |
| #include <unordered_map> |
| |
| #include <gtest/gtest.h> |
| -#include <rapidjson/document.h> |
| -#include <rapidjson/filewritestream.h> |
| -#include <rapidjson/istreamwrapper.h> |
| -#include <rapidjson/prettywriter.h> |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| +# include <rapidjson/document.h> |
| +# include <rapidjson/filewritestream.h> |
| +# include <rapidjson/istreamwrapper.h> |
| +# include <rapidjson/prettywriter.h> |
| +#endif |
| |
| // We directly call into a function to register the parameterized tests. This saves spinning up |
| // a subprocess with a new gtest filter. |
| -#include <gtest/../../src/gtest-internal-inl.h> |
| +#include <gtest/src/gtest-internal-inl.h> |
| |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| namespace js = rapidjson; |
| +#endif |
| |
| namespace angle |
| { |
| @@ -45,6 +49,7 @@ constexpr char kFilterFileArg[] = "--filter-file"; |
| constexpr char kResultFileArg[] = "--results-file"; |
| constexpr char kTestTimeoutArg[] = "--test-timeout"; |
| constexpr char kDisableCrashHandler[] = "--disable-crash-handler"; |
| +constexpr char kDisableDebugLayers[] = "--disable-debug-layers"; |
| constexpr char kIsolatedOutDir[] = "--isolated-outdir"; |
| |
| constexpr char kStartedTestString[] = "[ RUN ] "; |
| @@ -140,6 +145,7 @@ const char *ResultTypeToString(TestResultType type) |
| } |
| } |
| |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| TestResultType GetResultTypeFromString(const std::string &str) |
| { |
| if (str == "CRASH") |
| @@ -156,12 +162,14 @@ TestResultType GetResultTypeFromString(const std::string &str) |
| return TestResultType::Timeout; |
| return TestResultType::Unknown; |
| } |
| +#endif |
| |
| bool IsFailedResult(TestResultType resultType) |
| { |
| return resultType != TestResultType::Pass && resultType != TestResultType::Skip; |
| } |
| |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| js::Value ResultTypeToJSString(TestResultType type, js::Document::AllocatorType *allocator) |
| { |
| js::Value jsName; |
| @@ -351,6 +359,7 @@ void WriteHistogramJson(const HistogramWriter &histogramWriter, const std::strin |
| printf("Error writing histogram json file.\n"); |
| } |
| } |
| +#endif // defined(ANGLE_HAS_RAPIDJSON) |
| |
| void UpdateCurrentTestResult(const testing::TestResult &resultIn, TestResults *resultsOut) |
| { |
| @@ -466,6 +475,7 @@ std::string GetTestFilter(const std::vector<TestIdentifier> &tests) |
| return filterStream.str(); |
| } |
| |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| bool GetTestArtifactsFromJSON(const js::Value::ConstObject &obj, |
| std::vector<std::string> *testArtifactPathsOut) |
| { |
| @@ -650,6 +660,7 @@ bool GetTestResultsFromJSON(const js::Document &document, TestResults *resultsOu |
| |
| return true; |
| } |
| +#endif // defined(ANGLE_HAS_RAPIDJSON) |
| |
| bool MergeTestResults(TestResults *input, TestResults *output, int flakyRetries) |
| { |
| @@ -1131,7 +1142,7 @@ TestSuite::TestSuite(int *argc, char **argv, std::function<void()> registerTests |
| Optional<int> filterArgIndex; |
| bool alsoRunDisabledTests = false; |
| |
| -#if defined(ANGLE_PLATFORM_MACOS) |
| +#if defined(ANGLE_PLATFORM_MACOS) && defined(ANGLE_OUTSIDE_WEBKIT) |
| // By default, we should hook file API functions on macOS to avoid slow Metal shader caching |
| // file access. |
| angle::InitMetalFileAPIHooking(*argc, argv); |
| @@ -1201,6 +1212,19 @@ TestSuite::TestSuite(int *argc, char **argv, std::function<void()> registerTests |
| mCrashCallback = [this]() { onCrashOrTimeout(TestResultType::Crash); }; |
| InitCrashHandler(&mCrashCallback); |
| } |
| + if (!mDisableDebugLayers) |
| + { |
| +#if defined(ANGLE_ENABLE_METAL) |
| + // Metal does not support toggling per-context debug layers for tests. |
| + SetEnvironmentVar("MTL_DEBUG_LAYER", "1"); |
| + // Shader validation is not working for simulator. |
| +#if !TARGET_OS_SIMULATOR |
| + SetEnvironmentVar("MTL_SHADER_VALIDATION", "1"); |
| + SetEnvironmentVar("MTL_SHADER_VALIDATION_ABORT_ON_FAULT", "1"); |
| + SetEnvironmentVar("MTL_SHADER_VALIDATION_REPORT_TO_STDERR", "1"); |
| +#endif |
| +#endif |
| + } |
| |
| #if defined(ANGLE_PLATFORM_WINDOWS) || defined(ANGLE_PLATFORM_LINUX) |
| if (IsASan()) |
| @@ -1209,7 +1233,6 @@ TestSuite::TestSuite(int *argc, char **argv, std::function<void()> registerTests |
| SetEnvironmentVar(kVkLoaderDisableDLLUnloadingEnvVar, "1"); |
| } |
| #endif |
| - |
| registerTestsCallback(); |
| |
| std::string envShardIndex = angle::GetEnvironmentVar("GTEST_SHARD_INDEX"); |
| @@ -1467,7 +1490,8 @@ bool TestSuite::parseSingleArg(int *argc, char **argv, int argIndex) |
| ParseFlag("--gtest_list_tests", argc, argv, argIndex, &mGTestListTests) || |
| ParseFlag("--list-tests", argc, argv, argIndex, &mListTests) || |
| ParseFlag("--print-test-stdout", argc, argv, argIndex, &mPrintTestStdout) || |
| - ParseFlag(kDisableCrashHandler, argc, argv, argIndex, &mDisableCrashHandler); |
| + ParseFlag(kDisableCrashHandler, argc, argv, argIndex, &mDisableCrashHandler) || |
| + ParseFlag(kDisableDebugLayers, argc, argv, argIndex, &mDisableDebugLayers); |
| } |
| |
| void TestSuite::onCrashOrTimeout(TestResultType crashOrTimeout) |
| @@ -2038,7 +2062,9 @@ void TestSuite::addHistogramSample(const std::string &measurement, |
| double value, |
| const std::string &units) |
| { |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| mHistogramWriter.addSample(measurement, story, value, units); |
| +#endif // defined(ANGLE_HAS_RAPIDJSON) |
| } |
| |
| bool TestSuite::hasTestArtifactsDirectory() const |
| @@ -2062,6 +2088,7 @@ std::string TestSuite::reserveTestArtifactPath(const std::string &artifactName) |
| |
| bool GetTestResultsFromFile(const char *fileName, TestResults *resultsOut) |
| { |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| std::ifstream ifs(fileName); |
| if (!ifs.is_open()) |
| { |
| @@ -2086,6 +2113,9 @@ bool GetTestResultsFromFile(const char *fileName, TestResults *resultsOut) |
| } |
| |
| return true; |
| +#else |
| + return false; |
| +#endif // defined(ANGLE_HAS_RAPIDJSON) |
| } |
| |
| void TestSuite::dumpTestExpectationsErrorMessages() |
| @@ -2166,6 +2196,7 @@ int TestSuite::getSlowTestTimeout() const |
| |
| void TestSuite::writeOutputFiles(bool interrupted) |
| { |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| if (!mResultsFile.empty()) |
| { |
| WriteResultsFile(interrupted, mTestResults, mResultsFile); |
| @@ -2175,6 +2206,7 @@ void TestSuite::writeOutputFiles(bool interrupted) |
| { |
| WriteHistogramJson(mHistogramWriter, mHistogramJsonFile); |
| } |
| +#endif // defined(ANGLE_HAS_RAPIDJSON) |
| |
| mMetricWriter.close(); |
| } |
| diff --git a/src/tests/test_utils/runner/TestSuite.h b/src/tests/test_utils/runner/TestSuite.h |
| index 43108d062545d2bd52e2adcec26615c263c93d1a..eff93edbc71c18a793ff0db6c0ba962f7f8d8c7d 100644 |
| --- a/src/tests/test_utils/runner/TestSuite.h |
| +++ b/src/tests/test_utils/runner/TestSuite.h |
| @@ -16,10 +16,13 @@ |
| #include <string> |
| #include <thread> |
| |
| -#include "HistogramWriter.h" |
| #include "tests/test_expectations/GPUTestExpectationsParser.h" |
| #include "util/test_utils.h" |
| |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| +# include "HistogramWriter.h" |
| +#endif |
| + |
| namespace angle |
| { |
| struct TestIdentifier |
| @@ -217,6 +220,7 @@ class TestSuite |
| bool mListTests; |
| bool mPrintTestStdout; |
| bool mDisableCrashHandler; |
| + bool mDisableDebugLayers{false}; |
| int mBatchSize; |
| int mCurrentResultCount; |
| int mTotalResultCount; |
| @@ -232,7 +236,9 @@ class TestSuite |
| std::map<TestIdentifier, FileLine> mTestFileLines; |
| std::vector<ProcessInfo> mCurrentProcesses; |
| std::thread mWatchdogThread; |
| +#if defined(ANGLE_HAS_RAPIDJSON) |
| HistogramWriter mHistogramWriter; |
| +#endif |
| MetricWriter mMetricWriter; |
| std::string mTestArtifactDirectory; |
| GPUTestExpectationsParser mTestExpectationsParser; |
| diff --git a/third_party/zlib/google/compression_utils_portable.cc b/third_party/zlib/google/compression_utils_portable.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..49d6bfe9ea6ed4e42788087e8f35c2bfe1e52acc |
| --- /dev/null |
| +++ b/third_party/zlib/google/compression_utils_portable.cc |
| @@ -0,0 +1,205 @@ |
| +/* compression_utils_portable.cc |
| + * |
| + * Copyright 2019 The Chromium Authors |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the Chromium source repository LICENSE file. |
| + */ |
| + |
| +#include "compression_utils_portable.h" |
| + |
| +#include <stddef.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| + |
| +namespace zlib_internal { |
| + |
| +// The difference in bytes between a zlib header and a gzip header. |
| +const size_t kGzipZlibHeaderDifferenceBytes = 16; |
| + |
| +// Pass an integer greater than the following get a gzip header instead of a |
| +// zlib header when calling deflateInit2() and inflateInit2(). |
| +const int kWindowBitsToGetGzipHeader = 16; |
| + |
| +// This describes the amount of memory zlib uses to compress data. It can go |
| +// from 1 to 9, with 8 being the default. For details, see: |
| +// http://www.zlib.net/manual.html (search for memLevel). |
| +const int kZlibMemoryLevel = 8; |
| + |
| +// The expected compressed size is based on the input size factored by |
| +// internal Zlib constants (e.g. window size, etc) plus the wrapper |
| +// header size. |
| +uLongf GzipExpectedCompressedSize(uLongf input_size) { |
| + return kGzipZlibHeaderDifferenceBytes + compressBound(input_size); |
| +} |
| + |
| +// The expected decompressed size is stored in the last |
| +// 4 bytes of |input| in LE. See https://tools.ietf.org/html/rfc1952#page-5 |
| +uint32_t GetGzipUncompressedSize(const Bytef* compressed_data, size_t length) { |
| + uint32_t size; |
| + if (length < sizeof(size)) |
| + return 0; |
| + |
| + memcpy(&size, &compressed_data[length - sizeof(size)], sizeof(size)); |
| +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
| + return size; |
| +#else |
| + return __builtin_bswap32(size); |
| +#endif |
| +} |
| + |
| +// The number of window bits determines the type of wrapper to use - see |
| +// https://cs.chromium.org/chromium/src/third_party/zlib/zlib.h?l=566 |
| +inline int ZlibStreamWrapperType(WrapperType type) { |
| + if (type == ZLIB) // zlib DEFLATE stream wrapper |
| + return MAX_WBITS; |
| + if (type == GZIP) // gzip DEFLATE stream wrapper |
| + return MAX_WBITS + kWindowBitsToGetGzipHeader; |
| + if (type == ZRAW) // no wrapper, use raw DEFLATE |
| + return -MAX_WBITS; |
| + return 0; |
| +} |
| + |
| +int GzipCompressHelper(Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length, |
| + void* (*malloc_fn)(size_t), |
| + void (*free_fn)(void*)) { |
| + return CompressHelper(GZIP, dest, dest_length, source, source_length, |
| + Z_DEFAULT_COMPRESSION, malloc_fn, free_fn); |
| +} |
| + |
| +// This code is taken almost verbatim from third_party/zlib/compress.c. The only |
| +// difference is deflateInit2() is called which allows different window bits to |
| +// be set. > 16 causes a gzip header to be emitted rather than a zlib header, |
| +// and negative causes no header to emitted. |
| +// |
| +// Compression level can be a number from 1-9, with 1 being the fastest, 9 being |
| +// the best compression. The default, which the GZIP helper uses, is 6. |
| +int CompressHelper(WrapperType wrapper_type, |
| + Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length, |
| + int compression_level, |
| + void* (*malloc_fn)(size_t), |
| + void (*free_fn)(void*)) { |
| + if (compression_level < 0 || compression_level > 9) { |
| + compression_level = Z_DEFAULT_COMPRESSION; |
| + } |
| + |
| + z_stream stream; |
| + |
| + // FIXME(cavalcantii): z_const is not defined as 'const'. |
| + stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source)); |
| + stream.avail_in = static_cast<uInt>(source_length); |
| + stream.next_out = dest; |
| + stream.avail_out = static_cast<uInt>(*dest_length); |
| + if (static_cast<uLong>(stream.avail_out) != *dest_length) |
| + return Z_BUF_ERROR; |
| + |
| + // Cannot convert capturing lambdas to function pointers directly, hence the |
| + // structure. |
| + struct MallocFreeFunctions { |
| + void* (*malloc_fn)(size_t); |
| + void (*free_fn)(void*); |
| + } malloc_free = {malloc_fn, free_fn}; |
| + |
| + if (malloc_fn) { |
| + if (!free_fn) |
| + return Z_BUF_ERROR; |
| + |
| + auto zalloc = [](void* opaque, uInt items, uInt size) { |
| + return reinterpret_cast<MallocFreeFunctions*>(opaque)->malloc_fn(items * |
| + size); |
| + }; |
| + auto zfree = [](void* opaque, void* address) { |
| + return reinterpret_cast<MallocFreeFunctions*>(opaque)->free_fn(address); |
| + }; |
| + |
| + stream.zalloc = static_cast<alloc_func>(zalloc); |
| + stream.zfree = static_cast<free_func>(zfree); |
| + stream.opaque = static_cast<voidpf>(&malloc_free); |
| + } else { |
| + stream.zalloc = static_cast<alloc_func>(0); |
| + stream.zfree = static_cast<free_func>(0); |
| + stream.opaque = static_cast<voidpf>(0); |
| + } |
| + |
| + int err = deflateInit2(&stream, compression_level, Z_DEFLATED, |
| + ZlibStreamWrapperType(wrapper_type), kZlibMemoryLevel, |
| + Z_DEFAULT_STRATEGY); |
| + if (err != Z_OK) |
| + return err; |
| + |
| + // This has to exist outside of the if statement to prevent it going off the |
| + // stack before deflate(), which will use this object. |
| + gz_header gzip_header; |
| + if (wrapper_type == GZIP) { |
| + memset(&gzip_header, 0, sizeof(gzip_header)); |
| + err = deflateSetHeader(&stream, &gzip_header); |
| + if (err != Z_OK) |
| + return err; |
| + } |
| + |
| + err = deflate(&stream, Z_FINISH); |
| + if (err != Z_STREAM_END) { |
| + deflateEnd(&stream); |
| + return err == Z_OK ? Z_BUF_ERROR : err; |
| + } |
| + *dest_length = stream.total_out; |
| + |
| + err = deflateEnd(&stream); |
| + return err; |
| +} |
| + |
| +int GzipUncompressHelper(Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length) { |
| + return UncompressHelper(GZIP, dest, dest_length, source, source_length); |
| +} |
| + |
| +// This code is taken almost verbatim from third_party/zlib/uncompr.c. The only |
| +// difference is inflateInit2() is called which allows different window bits to |
| +// be set. > 16 causes a gzip header to be emitted rather than a zlib header, |
| +// and negative causes no header to emitted. |
| +int UncompressHelper(WrapperType wrapper_type, |
| + Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length) { |
| + z_stream stream; |
| + |
| + // FIXME(cavalcantii): z_const is not defined as 'const'. |
| + stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source)); |
| + stream.avail_in = static_cast<uInt>(source_length); |
| + if (static_cast<uLong>(stream.avail_in) != source_length) |
| + return Z_BUF_ERROR; |
| + |
| + stream.next_out = dest; |
| + stream.avail_out = static_cast<uInt>(*dest_length); |
| + if (static_cast<uLong>(stream.avail_out) != *dest_length) |
| + return Z_BUF_ERROR; |
| + |
| + stream.zalloc = static_cast<alloc_func>(0); |
| + stream.zfree = static_cast<free_func>(0); |
| + |
| + int err = inflateInit2(&stream, ZlibStreamWrapperType(wrapper_type)); |
| + if (err != Z_OK) |
| + return err; |
| + |
| + err = inflate(&stream, Z_FINISH); |
| + if (err != Z_STREAM_END) { |
| + inflateEnd(&stream); |
| + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) |
| + return Z_DATA_ERROR; |
| + return err; |
| + } |
| + *dest_length = stream.total_out; |
| + |
| + err = inflateEnd(&stream); |
| + return err; |
| +} |
| + |
| +} // namespace zlib_internal |
| diff --git a/third_party/zlib/google/compression_utils_portable.h b/third_party/zlib/google/compression_utils_portable.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..92b033e889f7f8afabeafe7108a1341a610ed832 |
| --- /dev/null |
| +++ b/third_party/zlib/google/compression_utils_portable.h |
| @@ -0,0 +1,63 @@ |
| +/* compression_utils_portable.h |
| + * |
| + * Copyright 2019 The Chromium Authors |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the Chromium source repository LICENSE file. |
| + */ |
| +#ifndef THIRD_PARTY_ZLIB_GOOGLE_COMPRESSION_UTILS_PORTABLE_H_ |
| +#define THIRD_PARTY_ZLIB_GOOGLE_COMPRESSION_UTILS_PORTABLE_H_ |
| + |
| +#include <stdint.h> |
| + |
| +/* TODO(cavalcantii): remove support for Chromium ever building with a system |
| + * zlib. |
| + */ |
| +#if defined(USE_SYSTEM_ZLIB) |
| +#include <zlib.h> |
| +/* AOSP build requires relative paths. */ |
| +#else |
| +#include "zlib.h" |
| +#endif |
| + |
| +namespace zlib_internal { |
| + |
| +enum WrapperType { |
| + ZLIB, |
| + GZIP, |
| + ZRAW, |
| +}; |
| + |
| +uLongf GzipExpectedCompressedSize(uLongf input_size); |
| + |
| +uint32_t GetGzipUncompressedSize(const Bytef* compressed_data, size_t length); |
| + |
| +int GzipCompressHelper(Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length, |
| + void* (*malloc_fn)(size_t), |
| + void (*free_fn)(void*)); |
| + |
| +int CompressHelper(WrapperType wrapper_type, |
| + Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length, |
| + int compression_level, |
| + void* (*malloc_fn)(size_t), |
| + void (*free_fn)(void*)); |
| + |
| +int GzipUncompressHelper(Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length); |
| + |
| +int UncompressHelper(WrapperType wrapper_type, |
| + Bytef* dest, |
| + uLongf* dest_length, |
| + const Bytef* source, |
| + uLong source_length); |
| + |
| +} // namespace zlib_internal |
| + |
| +#endif // THIRD_PARTY_ZLIB_GOOGLE_COMPRESSION_UTILS_PORTABLE_H_ |
| diff --git a/util/OSWindow.cpp b/util/OSWindow.cpp |
| index b57eea26ad74086c536b03727be9ea5ef7bd5ea8..e586f0fe0b6415699dd0e350bdf9b5cf06bb3587 100644 |
| --- a/util/OSWindow.cpp |
| +++ b/util/OSWindow.cpp |
| @@ -22,6 +22,10 @@ |
| # include "util/android/AndroidWindow.h" |
| #endif // defined(ANGLE_PLATFORM_ANDROID) |
| |
| +#if ANGLE_PLATFORM_IOS_FAMILY |
| +# include "util/ios/IOSWindow.h" |
| +#endif // ANGLE_PLATFORM_IOS_FAMILY |
| + |
| #ifndef DEBUG_EVENTS |
| # define DEBUG_EVENTS 0 |
| #endif |
| @@ -468,11 +472,16 @@ bool FindTestDataPath(const char *searchPath, char *dataPathOut, size_t maxDataP |
| AndroidWindow::GetApplicationDirectory() + "/chromium_tests_root"}; |
| #elif ANGLE_PLATFORM_IOS_FAMILY |
| const std::string searchPaths[] = {GetExecutableDirectory(), |
| - GetExecutableDirectory() + "/third_party/angle"}; |
| + GetExecutableDirectory() + "/third_party/angle", |
| + IOSWindow::GetResourcePath()}; |
| #else |
| - const std::string searchPaths[] = { |
| - GetExecutableDirectory(), GetExecutableDirectory() + "/../..", ".", |
| - GetExecutableDirectory() + "/../../third_party/angle", "third_party/angle"}; |
| + const std::string searchPaths[] = {GetExecutableDirectory(), |
| + GetExecutableDirectory() + "/../..", |
| + ".", |
| + GetExecutableDirectory() + "/../../third_party/angle", |
| + "third_party/angle", |
| + GetExecutableDirectory() + "/../../Source/ThirdParty/ANGLE", |
| + "Source/ThirdParty/ANGLE"}; |
| #endif // defined(ANGLE_PLATFORM_ANDROID) |
| |
| for (const std::string &path : searchPaths) |
| diff --git a/util/autogen/angle_features_autogen.cpp b/util/autogen/angle_features_autogen.cpp |
| index 9393dd208deb025840fd44419ab232a98139dd94..01d608414b28e8c4d3773238b5296cced0218bb1 100644 |
| --- a/util/autogen/angle_features_autogen.cpp |
| +++ b/util/autogen/angle_features_autogen.cpp |
| @@ -75,6 +75,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{ |
| {Feature::ClampPointSize, "clampPointSize"}, |
| {Feature::ClBestUniformFitWGS, "clBestUniformFitWGS"}, |
| {Feature::ClDumpVkSpirv, "clDumpVkSpirv"}, |
| + {Feature::ClearMsaaRg16UnormWithDrawWorkaround, "clearMsaaRg16UnormWithDrawWorkaround"}, |
| {Feature::ClearsWithGapsNeedFlush, "clearsWithGapsNeedFlush"}, |
| {Feature::ClipCullDistanceBrokenWithPassthroughShaders, "clipCullDistanceBrokenWithPassthroughShaders"}, |
| {Feature::ClipSrcRegionForBlitFramebuffer, "clipSrcRegionForBlitFramebuffer"}, |
| @@ -232,6 +233,7 @@ constexpr PackedEnumMap<Feature, const char *> kFeatureNames = {{ |
| {Feature::HasShaderStencilOutput, "hasShaderStencilOutput"}, |
| {Feature::HasStencilAutoResolve, "hasStencilAutoResolve"}, |
| {Feature::HasTextureSwizzle, "hasTextureSwizzle"}, |
| + {Feature::HasVariableRasterizationRate, "hasVariableRasterizationRate"}, |
| {Feature::InitFragmentOutputVariables, "initFragmentOutputVariables"}, |
| {Feature::InitializeColorAttachmentWithWhite, "initializeColorAttachmentWithWhite"}, |
| {Feature::InitializeCurrentVertexAttributes, "initializeCurrentVertexAttributes"}, |
| diff --git a/util/autogen/angle_features_autogen.h b/util/autogen/angle_features_autogen.h |
| index 5685afb9a0977be5600b4d102a9631f1424f498d..93733f0da7fc602c836d3aaeb9af91d019fc5eb4 100644 |
| --- a/util/autogen/angle_features_autogen.h |
| +++ b/util/autogen/angle_features_autogen.h |
| @@ -75,6 +75,7 @@ enum class Feature |
| ClampPointSize, |
| ClBestUniformFitWGS, |
| ClDumpVkSpirv, |
| + ClearMsaaRg16UnormWithDrawWorkaround, |
| ClearsWithGapsNeedFlush, |
| ClipCullDistanceBrokenWithPassthroughShaders, |
| ClipSrcRegionForBlitFramebuffer, |
| @@ -232,6 +233,7 @@ enum class Feature |
| HasShaderStencilOutput, |
| HasStencilAutoResolve, |
| HasTextureSwizzle, |
| + HasVariableRasterizationRate, |
| InitFragmentOutputVariables, |
| InitializeColorAttachmentWithWhite, |
| InitializeCurrentVertexAttributes, |
| diff --git a/util/capture/frame_capture_replay_autogen.cpp b/util/capture/frame_capture_replay_autogen.cpp |
| index ddef77cd831a07a86ae891e2d89c05d9b80f0db5..dd6c30f91e5fb7315a3cde2d9591ac9ba6d124cc 100644 |
| --- a/util/capture/frame_capture_replay_autogen.cpp |
| +++ b/util/capture/frame_capture_replay_autogen.cpp |
| @@ -105,6 +105,10 @@ void ReplayTraceFunctionCall(const CallCapture &call, const TraceFunctionMap &cu |
| captures[3].value.GLbooleanVal, captures[4].value.GLintVal, |
| captures[5].value.GLenumVal, captures[6].value.GLenumVal); |
| break; |
| + case angle::EntryPoint::GLBindMetalRasterizationRateMapANGLE: |
| + glBindMetalRasterizationRateMapANGLE( |
| + captures[0].value.GLuintVal, captures[1].value.GLMTLRasterizationRateMapANGLEVal); |
| + break; |
| case angle::EntryPoint::GLBindProgramPipeline: |
| glBindProgramPipeline(gProgramPipelineMap[captures[0].value.GLuintVal]); |
| break; |
| @@ -1024,6 +1028,11 @@ void ReplayTraceFunctionCall(const CallCapture &call, const TraceFunctionMap &cu |
| captures[2].value.GLenumVal, |
| gRenderbufferMap[captures[3].value.GLuintVal]); |
| break; |
| + case angle::EntryPoint::GLFramebufferResolveRenderbufferWEBKIT: |
| + glFramebufferResolveRenderbufferWEBKIT( |
| + captures[0].value.GLenumVal, captures[1].value.GLenumVal, |
| + captures[2].value.GLenumVal, gRenderbufferMap[captures[3].value.GLuintVal]); |
| + break; |
| case angle::EntryPoint::GLFramebufferShadingRateEXT: |
| glFramebufferShadingRateEXT(captures[0].value.GLenumVal, captures[1].value.GLenumVal, |
| captures[2].value.GLuintVal, captures[3].value.GLintVal, |
| diff --git a/util/capture/trace_gles_loader_autogen.cpp b/util/capture/trace_gles_loader_autogen.cpp |
| index 81097cb0ece18bd196ab4f09944ce8eaf525bb5c..f7a54fe76a196241c9c2ec5203da5f9b6f5b2836 100644 |
| --- a/util/capture/trace_gles_loader_autogen.cpp |
| +++ b/util/capture/trace_gles_loader_autogen.cpp |
| @@ -603,6 +603,8 @@ ANGLE_TRACE_LOADER_EXPORT PFNGLSAMPLEMASKIANGLEPROC t_glSampleMaskiANGLE; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLTEXSTORAGE2DMULTISAMPLEANGLEPROC t_glTexStorage2DMultisampleANGLE; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC |
| t_glGetTranslatedShaderSourceANGLE; |
| +ANGLE_TRACE_LOADER_EXPORT PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC |
| + t_glBindMetalRasterizationRateMapANGLE; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLACQUIRETEXTURESANGLEPROC t_glAcquireTexturesANGLE; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLRELEASETEXTURESANGLEPROC t_glReleaseTexturesANGLE; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC t_glBindUniformLocationCHROMIUM; |
| @@ -858,6 +860,8 @@ ANGLE_TRACE_LOADER_EXPORT PFNGLTEXTUREFOVEATIONPARAMETERSQCOMPROC |
| t_glTextureFoveationParametersQCOM; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLENDTILINGQCOMPROC t_glEndTilingQCOM; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLSTARTTILINGQCOMPROC t_glStartTilingQCOM; |
| +ANGLE_TRACE_LOADER_EXPORT PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC |
| + t_glFramebufferResolveRenderbufferWEBKIT; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLBLENDEQUATIONOESPROC t_glBlendEquationOES; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLDRAWTEXFOESPROC t_glDrawTexfOES; |
| ANGLE_TRACE_LOADER_EXPORT PFNGLDRAWTEXFVOESPROC t_glDrawTexfvOES; |
| @@ -1782,6 +1786,9 @@ void LoadTraceGLES(LoadProc loadProc) |
| loadProc("glTexStorage2DMultisampleANGLE")); |
| t_glGetTranslatedShaderSourceANGLE = reinterpret_cast<PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC>( |
| loadProc("glGetTranslatedShaderSourceANGLE")); |
| + t_glBindMetalRasterizationRateMapANGLE = |
| + reinterpret_cast<PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC>( |
| + loadProc("glBindMetalRasterizationRateMapANGLE")); |
| t_glAcquireTexturesANGLE = |
| reinterpret_cast<PFNGLACQUIRETEXTURESANGLEPROC>(loadProc("glAcquireTexturesANGLE")); |
| t_glReleaseTexturesANGLE = |
| @@ -2223,6 +2230,9 @@ void LoadTraceGLES(LoadProc loadProc) |
| loadProc("glTextureFoveationParametersQCOM")); |
| t_glEndTilingQCOM = reinterpret_cast<PFNGLENDTILINGQCOMPROC>(loadProc("glEndTilingQCOM")); |
| t_glStartTilingQCOM = reinterpret_cast<PFNGLSTARTTILINGQCOMPROC>(loadProc("glStartTilingQCOM")); |
| + t_glFramebufferResolveRenderbufferWEBKIT = |
| + reinterpret_cast<PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC>( |
| + loadProc("glFramebufferResolveRenderbufferWEBKIT")); |
| t_glBlendEquationOES = |
| reinterpret_cast<PFNGLBLENDEQUATIONOESPROC>(loadProc("glBlendEquationOES")); |
| t_glDrawTexfOES = reinterpret_cast<PFNGLDRAWTEXFOESPROC>(loadProc("glDrawTexfOES")); |
| diff --git a/util/capture/trace_gles_loader_autogen.h b/util/capture/trace_gles_loader_autogen.h |
| index c4605bba43feff2bcda1a078a6f50b8a069463f8..90e95be65c0ffc7d6df25089475c6b07b3e66f7a 100644 |
| --- a/util/capture/trace_gles_loader_autogen.h |
| +++ b/util/capture/trace_gles_loader_autogen.h |
| @@ -579,6 +579,7 @@ |
| #define glSampleMaskiANGLE t_glSampleMaskiANGLE |
| #define glTexStorage2DMultisampleANGLE t_glTexStorage2DMultisampleANGLE |
| #define glGetTranslatedShaderSourceANGLE t_glGetTranslatedShaderSourceANGLE |
| +#define glBindMetalRasterizationRateMapANGLE t_glBindMetalRasterizationRateMapANGLE |
| #define glAcquireTexturesANGLE t_glAcquireTexturesANGLE |
| #define glReleaseTexturesANGLE t_glReleaseTexturesANGLE |
| #define glBindUniformLocationCHROMIUM t_glBindUniformLocationCHROMIUM |
| @@ -817,6 +818,7 @@ |
| #define glTextureFoveationParametersQCOM t_glTextureFoveationParametersQCOM |
| #define glEndTilingQCOM t_glEndTilingQCOM |
| #define glStartTilingQCOM t_glStartTilingQCOM |
| +#define glFramebufferResolveRenderbufferWEBKIT t_glFramebufferResolveRenderbufferWEBKIT |
| #define glBlendEquationOES t_glBlendEquationOES |
| #define glDrawTexfOES t_glDrawTexfOES |
| #define glDrawTexfvOES t_glDrawTexfvOES |
| @@ -1477,6 +1479,8 @@ ANGLE_TRACE_LOADER_EXPORT extern PFNGLTEXSTORAGE2DMULTISAMPLEANGLEPROC |
| t_glTexStorage2DMultisampleANGLE; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC |
| t_glGetTranslatedShaderSourceANGLE; |
| +ANGLE_TRACE_LOADER_EXPORT extern PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC |
| + t_glBindMetalRasterizationRateMapANGLE; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLACQUIRETEXTURESANGLEPROC t_glAcquireTexturesANGLE; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLRELEASETEXTURESANGLEPROC t_glReleaseTexturesANGLE; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC |
| @@ -1749,6 +1753,8 @@ ANGLE_TRACE_LOADER_EXPORT extern PFNGLTEXTUREFOVEATIONPARAMETERSQCOMPROC |
| t_glTextureFoveationParametersQCOM; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLENDTILINGQCOMPROC t_glEndTilingQCOM; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLSTARTTILINGQCOMPROC t_glStartTilingQCOM; |
| +ANGLE_TRACE_LOADER_EXPORT extern PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC |
| + t_glFramebufferResolveRenderbufferWEBKIT; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLBLENDEQUATIONOESPROC t_glBlendEquationOES; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLDRAWTEXFOESPROC t_glDrawTexfOES; |
| ANGLE_TRACE_LOADER_EXPORT extern PFNGLDRAWTEXFVOESPROC t_glDrawTexfvOES; |
| diff --git a/util/capture/trace_interpreter_autogen.cpp b/util/capture/trace_interpreter_autogen.cpp |
| index f32f53c8d4b56b5640bb8ab5bc5b8f97f973a381..376442bf20fffdf28bd2c6eaeeecfc79b1326e07 100644 |
| --- a/util/capture/trace_interpreter_autogen.cpp |
| +++ b/util/capture/trace_interpreter_autogen.cpp |
| @@ -910,6 +910,13 @@ CallCapture ParseCallCapture(const Token &nameToken, |
| paramTokens, strings); |
| return CallCapture(EntryPoint::GLBindImageTexture, std::move(params)); |
| } |
| + if (strcmp(nameToken, "glBindMetalRasterizationRateMapANGLE") == 0) |
| + { |
| + ParamBuffer params = |
| + ParseParameters<std::remove_pointer<PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC>::type>( |
| + paramTokens, strings); |
| + return CallCapture(EntryPoint::GLBindMetalRasterizationRateMapANGLE, std::move(params)); |
| + } |
| if (strcmp(nameToken, "glBindProgramPipeline") == 0) |
| { |
| ParamBuffer params = |
| @@ -2282,6 +2289,13 @@ CallCapture ParseCallCapture(const Token &nameToken, |
| paramTokens, strings); |
| return CallCapture(EntryPoint::GLFramebufferRenderbufferOES, std::move(params)); |
| } |
| + if (strcmp(nameToken, "glFramebufferResolveRenderbufferWEBKIT") == 0) |
| + { |
| + ParamBuffer params = ParseParameters< |
| + std::remove_pointer<PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC>::type>(paramTokens, |
| + strings); |
| + return CallCapture(EntryPoint::GLFramebufferResolveRenderbufferWEBKIT, std::move(params)); |
| + } |
| if (strcmp(nameToken, "glFramebufferShadingRateEXT") == 0) |
| { |
| ParamBuffer params = |
| diff --git a/util/gles_loader_autogen.cpp b/util/gles_loader_autogen.cpp |
| index 747ff9522fb771e279eb8b8bbf637073401768c6..c1f1ebda081cda7d04402d3b25eace3e0dc5418d 100644 |
| --- a/util/gles_loader_autogen.cpp |
| +++ b/util/gles_loader_autogen.cpp |
| @@ -587,6 +587,8 @@ ANGLE_UTIL_EXPORT PFNGLGETMULTISAMPLEFVANGLEPROC l_glGetMultisamplefvANGLE; |
| ANGLE_UTIL_EXPORT PFNGLSAMPLEMASKIANGLEPROC l_glSampleMaskiANGLE; |
| ANGLE_UTIL_EXPORT PFNGLTEXSTORAGE2DMULTISAMPLEANGLEPROC l_glTexStorage2DMultisampleANGLE; |
| ANGLE_UTIL_EXPORT PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC l_glGetTranslatedShaderSourceANGLE; |
| +ANGLE_UTIL_EXPORT PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC |
| + l_glBindMetalRasterizationRateMapANGLE; |
| ANGLE_UTIL_EXPORT PFNGLACQUIRETEXTURESANGLEPROC l_glAcquireTexturesANGLE; |
| ANGLE_UTIL_EXPORT PFNGLRELEASETEXTURESANGLEPROC l_glReleaseTexturesANGLE; |
| ANGLE_UTIL_EXPORT PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC l_glBindUniformLocationCHROMIUM; |
| @@ -834,6 +836,8 @@ ANGLE_UTIL_EXPORT PFNGLSHADINGRATEQCOMPROC l_glShadingRateQCOM; |
| ANGLE_UTIL_EXPORT PFNGLTEXTUREFOVEATIONPARAMETERSQCOMPROC l_glTextureFoveationParametersQCOM; |
| ANGLE_UTIL_EXPORT PFNGLENDTILINGQCOMPROC l_glEndTilingQCOM; |
| ANGLE_UTIL_EXPORT PFNGLSTARTTILINGQCOMPROC l_glStartTilingQCOM; |
| +ANGLE_UTIL_EXPORT PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC |
| + l_glFramebufferResolveRenderbufferWEBKIT; |
| ANGLE_UTIL_EXPORT PFNGLBLENDEQUATIONOESPROC l_glBlendEquationOES; |
| ANGLE_UTIL_EXPORT PFNGLDRAWTEXFOESPROC l_glDrawTexfOES; |
| ANGLE_UTIL_EXPORT PFNGLDRAWTEXFVOESPROC l_glDrawTexfvOES; |
| @@ -1757,6 +1761,9 @@ void LoadUtilGLES(LoadProc loadProc) |
| loadProc("glTexStorage2DMultisampleANGLE")); |
| l_glGetTranslatedShaderSourceANGLE = reinterpret_cast<PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC>( |
| loadProc("glGetTranslatedShaderSourceANGLE")); |
| + l_glBindMetalRasterizationRateMapANGLE = |
| + reinterpret_cast<PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC>( |
| + loadProc("glBindMetalRasterizationRateMapANGLE")); |
| l_glAcquireTexturesANGLE = |
| reinterpret_cast<PFNGLACQUIRETEXTURESANGLEPROC>(loadProc("glAcquireTexturesANGLE")); |
| l_glReleaseTexturesANGLE = |
| @@ -2198,6 +2205,9 @@ void LoadUtilGLES(LoadProc loadProc) |
| loadProc("glTextureFoveationParametersQCOM")); |
| l_glEndTilingQCOM = reinterpret_cast<PFNGLENDTILINGQCOMPROC>(loadProc("glEndTilingQCOM")); |
| l_glStartTilingQCOM = reinterpret_cast<PFNGLSTARTTILINGQCOMPROC>(loadProc("glStartTilingQCOM")); |
| + l_glFramebufferResolveRenderbufferWEBKIT = |
| + reinterpret_cast<PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC>( |
| + loadProc("glFramebufferResolveRenderbufferWEBKIT")); |
| l_glBlendEquationOES = |
| reinterpret_cast<PFNGLBLENDEQUATIONOESPROC>(loadProc("glBlendEquationOES")); |
| l_glDrawTexfOES = reinterpret_cast<PFNGLDRAWTEXFOESPROC>(loadProc("glDrawTexfOES")); |
| diff --git a/util/gles_loader_autogen.h b/util/gles_loader_autogen.h |
| index 3930024b0e9954d78f65dcf00c5d30fb597acbcd..1a8cb53e6e077c7fee71047bf1073740376d1df5 100644 |
| --- a/util/gles_loader_autogen.h |
| +++ b/util/gles_loader_autogen.h |
| @@ -579,6 +579,7 @@ |
| #define glSampleMaskiANGLE l_glSampleMaskiANGLE |
| #define glTexStorage2DMultisampleANGLE l_glTexStorage2DMultisampleANGLE |
| #define glGetTranslatedShaderSourceANGLE l_glGetTranslatedShaderSourceANGLE |
| +#define glBindMetalRasterizationRateMapANGLE l_glBindMetalRasterizationRateMapANGLE |
| #define glAcquireTexturesANGLE l_glAcquireTexturesANGLE |
| #define glReleaseTexturesANGLE l_glReleaseTexturesANGLE |
| #define glBindUniformLocationCHROMIUM l_glBindUniformLocationCHROMIUM |
| @@ -817,6 +818,7 @@ |
| #define glTextureFoveationParametersQCOM l_glTextureFoveationParametersQCOM |
| #define glEndTilingQCOM l_glEndTilingQCOM |
| #define glStartTilingQCOM l_glStartTilingQCOM |
| +#define glFramebufferResolveRenderbufferWEBKIT l_glFramebufferResolveRenderbufferWEBKIT |
| #define glBlendEquationOES l_glBlendEquationOES |
| #define glDrawTexfOES l_glDrawTexfOES |
| #define glDrawTexfvOES l_glDrawTexfvOES |
| @@ -1446,6 +1448,8 @@ ANGLE_UTIL_EXPORT extern PFNGLGETMULTISAMPLEFVANGLEPROC l_glGetMultisamplefvANGL |
| ANGLE_UTIL_EXPORT extern PFNGLSAMPLEMASKIANGLEPROC l_glSampleMaskiANGLE; |
| ANGLE_UTIL_EXPORT extern PFNGLTEXSTORAGE2DMULTISAMPLEANGLEPROC l_glTexStorage2DMultisampleANGLE; |
| ANGLE_UTIL_EXPORT extern PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC l_glGetTranslatedShaderSourceANGLE; |
| +ANGLE_UTIL_EXPORT extern PFNGLBINDMETALRASTERIZATIONRATEMAPANGLEPROC |
| + l_glBindMetalRasterizationRateMapANGLE; |
| ANGLE_UTIL_EXPORT extern PFNGLACQUIRETEXTURESANGLEPROC l_glAcquireTexturesANGLE; |
| ANGLE_UTIL_EXPORT extern PFNGLRELEASETEXTURESANGLEPROC l_glReleaseTexturesANGLE; |
| ANGLE_UTIL_EXPORT extern PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC l_glBindUniformLocationCHROMIUM; |
| @@ -1694,6 +1698,8 @@ ANGLE_UTIL_EXPORT extern PFNGLSHADINGRATEQCOMPROC l_glShadingRateQCOM; |
| ANGLE_UTIL_EXPORT extern PFNGLTEXTUREFOVEATIONPARAMETERSQCOMPROC l_glTextureFoveationParametersQCOM; |
| ANGLE_UTIL_EXPORT extern PFNGLENDTILINGQCOMPROC l_glEndTilingQCOM; |
| ANGLE_UTIL_EXPORT extern PFNGLSTARTTILINGQCOMPROC l_glStartTilingQCOM; |
| +ANGLE_UTIL_EXPORT extern PFNGLFRAMEBUFFERRESOLVERENDERBUFFERWEBKITPROC |
| + l_glFramebufferResolveRenderbufferWEBKIT; |
| ANGLE_UTIL_EXPORT extern PFNGLBLENDEQUATIONOESPROC l_glBlendEquationOES; |
| ANGLE_UTIL_EXPORT extern PFNGLDRAWTEXFOESPROC l_glDrawTexfOES; |
| ANGLE_UTIL_EXPORT extern PFNGLDRAWTEXFVOESPROC l_glDrawTexfvOES; |
| diff --git a/util/ios/IOSWindow.h b/util/ios/IOSWindow.h |
| index 9cfc1284aebf9dc1e8a6004cda2a55ddb10c30a5..d59c2db405ae8b2181df02c6cf509b2ec1c87514 100644 |
| --- a/util/ios/IOSWindow.h |
| +++ b/util/ios/IOSWindow.h |
| @@ -9,6 +9,8 @@ |
| #ifndef UTIL_IOS_WINDOW_H_ |
| #define UTIL_IOS_WINDOW_H_ |
| |
| +#include <string> |
| + |
| #include "common/debug.h" |
| #include "util/OSWindow.h" |
| |
| @@ -18,6 +20,8 @@ class IOSWindow : public OSWindow |
| IOSWindow() {} |
| ~IOSWindow() override {} |
| |
| + static std::string GetResourcePath(); |
| + |
| void disableErrorMessageDialog() override {} |
| void destroy() override {} |
| |
| diff --git a/util/ios/IOSWindow.mm b/util/ios/IOSWindow.mm |
| index 54943376418a3ab9e4509460c424bde4048f2bc1..bac9698d76d06d8f77afba72fd0b6f250478369f 100644 |
| --- a/util/ios/IOSWindow.mm |
| +++ b/util/ios/IOSWindow.mm |
| @@ -48,3 +48,12 @@ OSWindow *OSWindow::New(void * /*nativeDisplay*/) |
| { |
| return new IOSWindow; |
| } |
| + |
| +// static |
| +std::string IOSWindow::GetResourcePath() |
| +{ |
| + NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; |
| + if (!resourcePath) |
| + return {}; |
| + return [resourcePath UTF8String]; |
| +} |
| diff --git a/util/ios/ios_main.mm b/util/ios/ios_main.mm |
| index 6df44200413599cbee17741ac8d74380f694bdff..ad419fa769f2a7d9cf222d4eba8b63be26b9b261 100644 |
| --- a/util/ios/ios_main.mm |
| +++ b/util/ios/ios_main.mm |
| @@ -10,11 +10,12 @@ |
| #import <UIKit/UIKit.h> |
| |
| #include <stdio.h> |
| +#include <unistd.h> |
| |
| static int original_argc; |
| -static char **original_argv; |
| +static char *_Nullable *_Nullable original_argv = nullptr; |
| |
| -int main(int argc, char **argv); |
| +int main(int argc, char *_Nullable *_Nullable argv); |
| |
| @interface AngleUtilAppDelegate : UIResponder <UIApplicationDelegate> |
| |
| @@ -28,11 +29,12 @@ @synthesize window; |
| |
| - (void)runMain |
| { |
| + chdir([NSTemporaryDirectory() fileSystemRepresentation]); |
| exit(main(original_argc, original_argv)); |
| } |
| |
| -- (BOOL)application:(UIApplication *)application |
| - didFinishLaunchingWithOptions:(NSDictionary *)launchOptions |
| +- (BOOL)application:(UIApplication *_Nonnull)application |
| + didFinishLaunchingWithOptions:(NSDictionary *_Nullable)launchOptions |
| { |
| self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; |
| self.window.rootViewController = [[UIViewController alloc] initWithNibName:nil bundle:nil]; |
| @@ -49,7 +51,7 @@ - (BOOL)application:(UIApplication *)application |
| |
| @end |
| |
| -extern "C" int ios_main(int argc, char **argv) |
| +extern "C" int ios_main(int argc, char *_Nonnull *_Nonnull argv) |
| { |
| original_argc = argc; |
| original_argv = argv; |
| diff --git a/util/osx/OSXWindow.mm b/util/osx/OSXWindow.mm |
| index c08e8f9b68ac84b50f960b77d600bdf009f594fc..5dc534bdc6872c5b1e28805e21c634a20e607c18 100644 |
| --- a/util/osx/OSXWindow.mm |
| +++ b/util/osx/OSXWindow.mm |
| @@ -128,9 +128,9 @@ - (id)initWithWindow:(OSXWindow *)window |
| return self; |
| } |
| |
| -- (void)onOSXWindowDeleted |
| +- (void)detach |
| { |
| - mWindow = nil; |
| + mWindow = nullptr; |
| } |
| |
| - (BOOL)windowShouldClose:(id)sender |
| @@ -704,7 +704,8 @@ void OSXWindow::destroy() |
| |
| [mView release]; |
| mView = nil; |
| - [mDelegate onOSXWindowDeleted]; |
| + [mWindow setDelegate:nil]; |
| + [mDelegate detach]; |
| [mDelegate release]; |
| mDelegate = nil; |
| // NSWindow won't be completely released unless its content view is set to nil: |
| diff --git a/util/posix/test_utils_posix.cpp b/util/posix/test_utils_posix.cpp |
| index 92dfa30ef88288bceddf4d4447ebeac2fa93311c..6e8acc86a08618278d542220dc8a95916a795656 100644 |
| --- a/util/posix/test_utils_posix.cpp |
| +++ b/util/posix/test_utils_posix.cpp |
| @@ -360,7 +360,9 @@ void WriteDebugMessage(const char *format, ...) |
| { |
| va_list vararg; |
| va_start(vararg, format); |
| + ANGLE_DISABLE_NONLITERAL_FORMAT_WARNING |
| vfprintf(stderr, format, vararg); |
| + ANGLE_REENABLE_NONLITERAL_FORMAT_WARNING |
| va_end(vararg); |
| } |