blob: 4804dae550cb41a8ccadc2fc0639a4aed48a841a [file] [edit]
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> &paramsInfo)
+{
+ const DrawBuffersAnyFormatVariationsTestParams &params = 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, &currentProgram);
+ 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 &params)
{
// 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 &params)
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 &params)
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);
}