aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoff Lang <geofflang@chromium.org>2024-04-05 13:25:12 -0400
committerAngle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com>2024-04-12 19:14:13 +0000
commit67fc293ab0b33e82cc151286f22d55a0781e9e86 (patch)
treebb5d3b630d23980ef3d3478d0b48bbc077fca146
parent5e790bfb16e8246bdf73e625bd4203ce761b959a (diff)
downloadangle-67fc293ab0b33e82cc151286f22d55a0781e9e86.tar.gz
WebGPU: Add shader translation and program linking stubs.
Add a TranslatorWGSL which outputs the same translated shaders every time. Implement the compile and link tasks. Bug: angleproject:8662 Change-Id: I62bbd6c528e1d671d0f4becc38f15f1eceb0336c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5428807 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Matthew Denton <mpdenton@chromium.org>
-rw-r--r--BUILD.gn5
-rw-r--r--include/GLSLANG/ShaderLang.h5
-rwxr-xr-xscripts/export_targets.py1
-rw-r--r--src/angle_program_serialize_data_version.gni8
-rw-r--r--src/compiler.gni3
-rw-r--r--src/compiler/translator/CodeGen.cpp15
-rw-r--r--src/compiler/translator/util.cpp4
-rw-r--r--src/compiler/translator/util.h1
-rw-r--r--src/compiler/translator/wgsl/TranslatorWGSL.cpp58
-rw-r--r--src/compiler/translator/wgsl/TranslatorWGSL.h29
-rw-r--r--src/libANGLE/renderer/wgpu/CompilerWgpu.cpp2
-rw-r--r--src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.cpp6
-rw-r--r--src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.h12
-rw-r--r--src/libANGLE/renderer/wgpu/ProgramWgpu.cpp127
-rw-r--r--src/libANGLE/renderer/wgpu/ShaderWgpu.cpp24
-rw-r--r--src/tests/gl_tests/RendererTest.cpp26
16 files changed, 315 insertions, 11 deletions
diff --git a/BUILD.gn b/BUILD.gn
index 834b707203..1a2710f81c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -755,6 +755,11 @@ template("translator_lib") {
sources += angle_translator_lib_msl_sources
defines += [ "ANGLE_ENABLE_METAL" ]
}
+
+ if (angle_enable_wgpu) {
+ sources += angle_translator_lib_wgsl_sources
+ defines += [ "ANGLE_ENABLE_WGPU" ]
+ }
}
if (_needs_glsl_base) {
diff --git a/include/GLSLANG/ShaderLang.h b/include/GLSLANG/ShaderLang.h
index 5eb4806568..0d2497540e 100644
--- a/include/GLSLANG/ShaderLang.h
+++ b/include/GLSLANG/ShaderLang.h
@@ -26,7 +26,7 @@
// Version number for shader translation API.
// It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 349
+#define ANGLE_SH_VERSION 350
enum ShShaderSpec
{
@@ -74,6 +74,9 @@ enum ShShaderOutput
// Output for MSL
SH_MSL_METAL_OUTPUT = 0x8B4D,
+
+ // Output for WGSL
+ SH_WGSL_OUTPUT = 0x8B4E,
};
struct ShCompileOptionsMetal
diff --git a/scripts/export_targets.py b/scripts/export_targets.py
index 11ea9e8aff..5a06940715 100755
--- a/scripts/export_targets.py
+++ b/scripts/export_targets.py
@@ -189,6 +189,7 @@ IGNORED_INCLUDES = {
b'compiler/translator/hlsl/TranslatorHLSL.h',
b'compiler/translator/msl/TranslatorMSL.h',
b'compiler/translator/spirv/TranslatorSPIRV.h',
+ b'compiler/translator/wgsl/TranslatorWGSL.h',
b'contrib/optimizations/slide_hash_neon.h',
b'dirent_on_windows.h',
b'dlopen_fuchsia.h',
diff --git a/src/angle_program_serialize_data_version.gni b/src/angle_program_serialize_data_version.gni
index 9453612459..d247714a97 100644
--- a/src/angle_program_serialize_data_version.gni
+++ b/src/angle_program_serialize_data_version.gni
@@ -17,6 +17,7 @@ import("libANGLE/renderer/gl/gl_backend.gni")
import("libANGLE/renderer/metal/metal_backend.gni")
import("libANGLE/renderer/null/null_backend.gni")
import("libANGLE/renderer/vulkan/vulkan_backend.gni")
+import("libANGLE/renderer/wgpu/wgpu_sources.gni")
import("libGLESv2.gni")
angle_code_affecting_program_serialize = libangle_common_sources
@@ -39,6 +40,7 @@ angle_code_affecting_program_serialize +=
angle_code_affecting_program_serialize +=
angle_translator_glsl_symbol_table_sources
angle_code_affecting_program_serialize += angle_translator_lib_msl_sources
+angle_code_affecting_program_serialize += angle_translator_lib_wgsl_sources
angle_code_affecting_program_serialize += angle_preprocessor_sources
angle_dependencies_affecting_program_serialize = []
@@ -79,6 +81,12 @@ if (angle_enable_metal) {
}
}
+if (angle_enable_wgpu) {
+ wgpu_backend_dir = "libANGLE/renderer/wgpu/"
+ angle_code_affecting_program_serialize +=
+ rebase_path(wgpu_backend_sources, angle_root, wgpu_backend_dir)
+}
+
if (angle_has_frame_capture) {
angle_code_affecting_program_serialize += libangle_capture_sources
}
diff --git a/src/compiler.gni b/src/compiler.gni
index 165055273b..c4feb4bbc5 100644
--- a/src/compiler.gni
+++ b/src/compiler.gni
@@ -449,6 +449,9 @@ angle_translator_lib_msl_sources = [
"src/compiler/translator/tree_ops/msl/WrapMain.h",
]
+angle_translator_lib_wgsl_sources =
+ [ "src/compiler/translator/wgsl/TranslatorWGSL.cpp" ]
+
angle_preprocessor_sources = [
"src/compiler/preprocessor/DiagnosticsBase.cpp",
"src/compiler/preprocessor/DiagnosticsBase.h",
diff --git a/src/compiler/translator/CodeGen.cpp b/src/compiler/translator/CodeGen.cpp
index 4c5b8b3d77..383bee94ca 100644
--- a/src/compiler/translator/CodeGen.cpp
+++ b/src/compiler/translator/CodeGen.cpp
@@ -24,6 +24,14 @@
# include "compiler/translator/msl/TranslatorMSL.h"
#endif // ANGLE_ENABLE_METAL
+#ifdef ANGLE_ENABLE_WEBGPU
+# include "compiler/translator/msl/TranslatorMSL.h"
+#endif // ANGLE_ENABLE_METAL
+
+#ifdef ANGLE_ENABLE_WGPU
+# include "compiler/translator/wgsl/TranslatorWGSL.h"
+#endif
+
#include "compiler/translator/util.h"
namespace sh
@@ -71,6 +79,13 @@ TCompiler *ConstructCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput
}
#endif // ANGLE_ENABLE_METAL
+#ifdef ANGLE_ENABLE_WGPU
+ if (IsOutputWGSL(output))
+ {
+ return new TranslatorWGSL(type, spec, output);
+ }
+#endif // ANGLE_ENABLE_WGPU
+
// Unsupported compiler or unknown format. Return nullptr per the sh::ConstructCompiler API.
return nullptr;
}
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
index 4c4c3fb778..40aa16dcf4 100644
--- a/src/compiler/translator/util.cpp
+++ b/src/compiler/translator/util.cpp
@@ -827,6 +827,10 @@ bool IsOutputMSL(ShShaderOutput output)
{
return output == SH_MSL_METAL_OUTPUT;
}
+bool IsOutputWGSL(ShShaderOutput output)
+{
+ return output == SH_WGSL_OUTPUT;
+}
bool IsInShaderStorageBlock(TIntermTyped *node)
{
diff --git a/src/compiler/translator/util.h b/src/compiler/translator/util.h
index 97765a74e7..872bca29a5 100644
--- a/src/compiler/translator/util.h
+++ b/src/compiler/translator/util.h
@@ -84,6 +84,7 @@ bool IsOutputGLSL(ShShaderOutput output);
bool IsOutputHLSL(ShShaderOutput output);
bool IsOutputSPIRV(ShShaderOutput output);
bool IsOutputMSL(ShShaderOutput output);
+bool IsOutputWGSL(ShShaderOutput output);
bool IsInShaderStorageBlock(TIntermTyped *node);
diff --git a/src/compiler/translator/wgsl/TranslatorWGSL.cpp b/src/compiler/translator/wgsl/TranslatorWGSL.cpp
new file mode 100644
index 0000000000..bb7c3be5d2
--- /dev/null
+++ b/src/compiler/translator/wgsl/TranslatorWGSL.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright 2024 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 "compiler/translator/wgsl/TranslatorWGSL.h"
+
+namespace sh
+{
+TranslatorWGSL::TranslatorWGSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
+ : TCompiler(type, spec, output)
+{}
+
+bool TranslatorWGSL::translate(TIntermBlock *root,
+ const ShCompileOptions &compileOptions,
+ PerformanceDiagnostics *perfDiagnostics)
+{
+ TInfoSinkBase &sink = getInfoSink().obj;
+ if (getShaderType() == GL_VERTEX_SHADER)
+ {
+ constexpr const char *kVertexShader = R"(@vertex
+fn main(@builtin(vertex_index) vertex_index : u32) -> @builtin(position) vec4f
+{
+ const pos = array(
+ vec2( 0.0, 0.5),
+ vec2(-0.5, -0.5),
+ vec2( 0.5, -0.5)
+ );
+
+ return vec4f(pos[vertex_index % 3], 0, 1);
+})";
+ sink << kVertexShader;
+ }
+ else if (getShaderType() == GL_FRAGMENT_SHADER)
+ {
+ constexpr const char *kFragmentShader = R"(@fragment
+fn main() -> @location(0) vec4f
+{
+ return vec4(1, 0, 0, 1);
+})";
+ sink << kFragmentShader;
+ }
+ else
+ {
+ UNREACHABLE();
+ return false;
+ }
+
+ return true;
+}
+
+bool TranslatorWGSL::shouldFlattenPragmaStdglInvariantAll()
+{
+ // Not neccesary for WGSL transformation.
+ return false;
+}
+} // namespace sh
diff --git a/src/compiler/translator/wgsl/TranslatorWGSL.h b/src/compiler/translator/wgsl/TranslatorWGSL.h
new file mode 100644
index 0000000000..d5c30e197a
--- /dev/null
+++ b/src/compiler/translator/wgsl/TranslatorWGSL.h
@@ -0,0 +1,29 @@
+//
+// Copyright 2024 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.
+//
+
+#ifndef COMPILER_TRANSLATOR_WGSL_H_
+#define COMPILER_TRANSLATOR_WGSL_H_
+
+#include "compiler/translator/Compiler.h"
+
+namespace sh
+{
+class TranslatorWGSL : public TCompiler
+{
+ public:
+ TranslatorWGSL(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output);
+
+ protected:
+ bool translate(TIntermBlock *root,
+ const ShCompileOptions &compileOptions,
+ PerformanceDiagnostics *perfDiagnostics) override;
+
+ [[nodiscard]] bool shouldFlattenPragmaStdglInvariantAll() override;
+};
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_WGSL_H_
diff --git a/src/libANGLE/renderer/wgpu/CompilerWgpu.cpp b/src/libANGLE/renderer/wgpu/CompilerWgpu.cpp
index 35572395b0..61d5edcd34 100644
--- a/src/libANGLE/renderer/wgpu/CompilerWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/CompilerWgpu.cpp
@@ -20,7 +20,7 @@ CompilerWgpu::~CompilerWgpu() {}
ShShaderOutput CompilerWgpu::getTranslatorOutputType() const
{
- return SH_ESSL_OUTPUT;
+ return SH_WGSL_OUTPUT;
}
} // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.cpp b/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.cpp
index 2ce7614176..d370660223 100644
--- a/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.cpp
@@ -115,4 +115,10 @@ void ProgramExecutableWgpu::getUniformuiv(const gl::Context *context,
{
// TODO: Write some values.
}
+
+TranslatedWGPUShaderModule &ProgramExecutableWgpu::getShaderModule(gl::ShaderType type)
+{
+ return mShaderModules[type];
+}
+
} // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.h b/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.h
index 9d198a9530..9a44ff02d3 100644
--- a/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.h
+++ b/src/libANGLE/renderer/wgpu/ProgramExecutableWgpu.h
@@ -12,6 +12,13 @@
#include "libANGLE/ProgramExecutable.h"
#include "libANGLE/renderer/ProgramExecutableImpl.h"
+#include <dawn/webgpu_cpp.h>
+
+struct TranslatedWGPUShaderModule
+{
+ wgpu::ShaderModule module;
+};
+
namespace rx
{
class ProgramExecutableWgpu : public ProgramExecutableImpl
@@ -74,6 +81,11 @@ class ProgramExecutableWgpu : public ProgramExecutableImpl
void getUniformfv(const gl::Context *context, GLint location, GLfloat *params) const override;
void getUniformiv(const gl::Context *context, GLint location, GLint *params) const override;
void getUniformuiv(const gl::Context *context, GLint location, GLuint *params) const override;
+
+ TranslatedWGPUShaderModule &getShaderModule(gl::ShaderType type);
+
+ private:
+ gl::ShaderMap<TranslatedWGPUShaderModule> mShaderModules;
};
} // namespace rx
diff --git a/src/libANGLE/renderer/wgpu/ProgramWgpu.cpp b/src/libANGLE/renderer/wgpu/ProgramWgpu.cpp
index 98598469b3..0b8819cfff 100644
--- a/src/libANGLE/renderer/wgpu/ProgramWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/ProgramWgpu.cpp
@@ -10,15 +10,112 @@
#include "libANGLE/renderer/wgpu/ProgramWgpu.h"
#include "common/debug.h"
+#include "libANGLE/renderer/wgpu/ProgramExecutableWgpu.h"
+#include "libANGLE/renderer/wgpu/wgpu_utils.h"
+#include "libANGLE/trace.h"
+
+#include <dawn/webgpu_cpp.h>
namespace rx
{
namespace
{
+class CreateWGPUShaderModuleTask : public LinkSubTask
+{
+ public:
+ CreateWGPUShaderModuleTask(wgpu::Instance instance,
+ wgpu::Device device,
+ const gl::SharedCompiledShaderState &compiledShaderState,
+ TranslatedWGPUShaderModule &resultShaderModule)
+ : mInstance(instance),
+ mDevice(device),
+ mCompiledShaderState(compiledShaderState),
+ mShaderModule(resultShaderModule)
+ {}
+
+ angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
+ {
+ infoLog << mLog.str();
+ return mResult;
+ }
+
+ void operator()() override
+ {
+ ANGLE_TRACE_EVENT0("gpu.angle", "CreateWGPUShaderModuleTask");
+
+ wgpu::ShaderModuleWGSLDescriptor shaderModuleWGSLDescriptor;
+ shaderModuleWGSLDescriptor.code = mCompiledShaderState->translatedSource.c_str();
+
+ wgpu::ShaderModuleDescriptor shaderModuleDescriptor;
+ shaderModuleDescriptor.nextInChain = &shaderModuleWGSLDescriptor;
+
+ mShaderModule.module = mDevice.CreateShaderModule(&shaderModuleDescriptor);
+
+ wgpu::CompilationInfoCallbackInfo callbackInfo;
+ callbackInfo.mode = wgpu::CallbackMode::WaitAnyOnly;
+ callbackInfo.callback = [](WGPUCompilationInfoRequestStatus status,
+ struct WGPUCompilationInfo const *compilationInfo,
+ void *userdata) {
+ CreateWGPUShaderModuleTask *task = static_cast<CreateWGPUShaderModuleTask *>(userdata);
+
+ if (status != WGPUCompilationInfoRequestStatus_Success)
+ {
+ task->mResult = angle::Result::Stop;
+ }
+
+ for (size_t msgIdx = 0; msgIdx < compilationInfo->messageCount; ++msgIdx)
+ {
+ const WGPUCompilationMessage &message = compilationInfo->messages[msgIdx];
+ switch (message.type)
+ {
+ case WGPUCompilationMessageType_Error:
+ task->mLog << "Error: ";
+ break;
+ case WGPUCompilationMessageType_Warning:
+ task->mLog << "Warning: ";
+ break;
+ case WGPUCompilationMessageType_Info:
+ task->mLog << "Info: ";
+ break;
+ default:
+ task->mLog << "Unknown: ";
+ break;
+ }
+ task->mLog << message.lineNum << ":" << message.linePos << ": " << message.message
+ << std::endl;
+ }
+ };
+ callbackInfo.userdata = this;
+
+ wgpu::FutureWaitInfo waitInfo;
+ waitInfo.future = mShaderModule.module.GetCompilationInfo(callbackInfo);
+
+ wgpu::WaitStatus waitStatus = mInstance.WaitAny(1, &waitInfo, -1);
+ if (waitStatus != wgpu::WaitStatus::Success)
+ {
+ mResult = angle::Result::Stop;
+ }
+ }
+
+ private:
+ wgpu::Instance mInstance;
+ wgpu::Device mDevice;
+ gl::SharedCompiledShaderState mCompiledShaderState;
+
+ TranslatedWGPUShaderModule &mShaderModule;
+
+ std::ostringstream mLog;
+ angle::Result mResult = angle::Result::Continue;
+};
+
class LinkTaskWgpu : public LinkTask
{
public:
+ LinkTaskWgpu(wgpu::Instance instance, wgpu::Device device, ProgramWgpu *program)
+ : mInstance(instance), mDevice(device), mProgram(program)
+ {}
~LinkTaskWgpu() override = default;
+
void link(const gl::ProgramLinkedResources &resources,
const gl::ProgramMergedVaryings &mergedVaryings,
std::vector<std::shared_ptr<LinkSubTask>> *linkSubTasksOut,
@@ -27,12 +124,32 @@ class LinkTaskWgpu : public LinkTask
ASSERT(linkSubTasksOut && linkSubTasksOut->empty());
ASSERT(postLinkSubTasksOut && postLinkSubTasksOut->empty());
- return;
+ ProgramExecutableWgpu *executable =
+ GetImplAs<ProgramExecutableWgpu>(&mProgram->getState().getExecutable());
+
+ const gl::ShaderMap<gl::SharedCompiledShaderState> &shaders =
+ mProgram->getState().getAttachedShaders();
+ for (gl::ShaderType shaderType : gl::AllShaderTypes())
+ {
+ if (shaders[shaderType])
+ {
+ auto task = std::make_shared<CreateWGPUShaderModuleTask>(
+ mInstance, mDevice, shaders[shaderType],
+ executable->getShaderModule(shaderType));
+ linkSubTasksOut->push_back(task);
+ }
+ }
}
+
angle::Result getResult(const gl::Context *context, gl::InfoLog &infoLog) override
{
return angle::Result::Continue;
}
+
+ private:
+ wgpu::Instance mInstance;
+ wgpu::Device mDevice;
+ ProgramWgpu *mProgram = nullptr;
};
} // anonymous namespace
@@ -56,10 +173,12 @@ void ProgramWgpu::setBinaryRetrievableHint(bool retrievable) {}
void ProgramWgpu::setSeparable(bool separable) {}
-angle::Result ProgramWgpu::link(const gl::Context *contextImpl,
- std::shared_ptr<LinkTask> *linkTaskOut)
+angle::Result ProgramWgpu::link(const gl::Context *context, std::shared_ptr<LinkTask> *linkTaskOut)
{
- *linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskWgpu);
+ wgpu::Device device = webgpu::GetDevice(context);
+ wgpu::Instance instance = webgpu::GetInstance(context);
+
+ *linkTaskOut = std::shared_ptr<LinkTask>(new LinkTaskWgpu(instance, device, this));
return angle::Result::Continue;
}
diff --git a/src/libANGLE/renderer/wgpu/ShaderWgpu.cpp b/src/libANGLE/renderer/wgpu/ShaderWgpu.cpp
index fe14e9c39a..92d981850e 100644
--- a/src/libANGLE/renderer/wgpu/ShaderWgpu.cpp
+++ b/src/libANGLE/renderer/wgpu/ShaderWgpu.cpp
@@ -12,10 +12,29 @@
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/ContextImpl.h"
+#include "libANGLE/trace.h"
namespace rx
{
+namespace
+{
+class ShaderTranslateTaskWgpu final : public ShaderTranslateTask
+{
+ bool translate(ShHandle compiler,
+ const ShCompileOptions &options,
+ const std::string &source) override
+ {
+ ANGLE_TRACE_EVENT1("gpu.angle", "ShaderTranslateTaskWgpu::translate", "source", source);
+
+ const char *srcStrings[] = {source.c_str()};
+ return sh::Compile(compiler, srcStrings, ArraySize(srcStrings), options);
+ }
+
+ void postTranslate(ShHandle compiler, const gl::CompiledShaderState &compiledState) override {}
+};
+} // namespace
+
ShaderWgpu::ShaderWgpu(const gl::ShaderState &data) : ShaderImpl(data) {}
ShaderWgpu::~ShaderWgpu() {}
@@ -28,7 +47,10 @@ std::shared_ptr<ShaderTranslateTask> ShaderWgpu::compile(const gl::Context *cont
{
options->pls = context->getImplementation()->getNativePixelLocalStorageOptions();
}
- return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask);
+
+ options->validateAST = true;
+
+ return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTaskWgpu);
}
std::string ShaderWgpu::getDebugInfo() const
diff --git a/src/tests/gl_tests/RendererTest.cpp b/src/tests/gl_tests/RendererTest.cpp
index 5e798cb8a3..2c1764b169 100644
--- a/src/tests/gl_tests/RendererTest.cpp
+++ b/src/tests/gl_tests/RendererTest.cpp
@@ -9,15 +9,15 @@
// configured incorrectly. For example, they might be using the D3D11 renderer when the test is
// meant to be using the D3D9 renderer.
+#include "common/string_utils.h"
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
+#include "util/shader_utils.h"
#include "util/test_utils.h"
-#include "common/string_utils.h"
-
using namespace angle;
-namespace
+namespace angle
{
class RendererTest : public ANGLETest<>
@@ -190,6 +190,24 @@ TEST_P(RendererTest, BufferData)
}
}
+// Compile simple vertex and fragment shaders
+TEST_P(RendererTest, CompileShader)
+{
+ GLuint vs = CompileShader(GL_VERTEX_SHADER, essl1_shaders::vs::Zero());
+ EXPECT_NE(vs, 0u);
+ glDeleteShader(vs);
+
+ GLuint fs = CompileShader(GL_FRAGMENT_SHADER, essl1_shaders::fs::Red());
+ EXPECT_NE(fs, 0u);
+ glDeleteShader(fs);
+}
+
+// Link a simple program
+TEST_P(RendererTest, LinkProgram)
+{
+ ANGLE_GL_PROGRAM(prog, essl1_shaders::vs::Zero(), essl1_shaders::fs::Red());
+}
+
// Select configurations (e.g. which renderer, which GLES major version) these tests should be run
// against.
// TODO(http://anglebug.com/8485): move ES2_WEBGPU to the definition of ANGLE_ALL_TEST_PLATFORMS_ES2
@@ -197,4 +215,4 @@ TEST_P(RendererTest, BufferData)
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND_ES31_AND_NULL_AND(RendererTest,
ANGLE_ALL_TEST_PLATFORMS_GL32_CORE,
ES2_WEBGPU());
-} // anonymous namespace
+} // namespace angle