| // |
| // 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 "tests/test_utils/CompilerTest.h" |
| |
| GLuint CompiledShader::compile(GLenum type, const char *source) |
| { |
| mShader = glCreateShader(type); |
| |
| const char *sourceArray[1] = {source}; |
| glShaderSource(mShader, 1, sourceArray, nullptr); |
| glCompileShader(mShader); |
| |
| GLint compileResult; |
| glGetShaderiv(mShader, GL_COMPILE_STATUS, &compileResult); |
| |
| GLint infoLogLength; |
| glGetShaderiv(mShader, GL_INFO_LOG_LENGTH, &infoLogLength); |
| mInfoLog.clear(); |
| |
| if (infoLogLength > 0) |
| { |
| std::vector<GLchar> infoLog(infoLogLength); |
| glGetShaderInfoLog(mShader, infoLogLength, nullptr, infoLog.data()); |
| |
| // Note: the info log is nul-terminated. |
| mInfoLog = infoLog.data(); |
| } |
| |
| if (compileResult == 0) |
| { |
| std::cerr << "shader compilation failed: " |
| << (mInfoLog.empty() ? "<Empty message log>" : mInfoLog.data()); |
| |
| destroy(); |
| } |
| else if (IsGLExtensionEnabled("GL_ANGLE_translated_shader_source")) |
| { |
| GLint translatedSourceLength; |
| glGetShaderiv(mShader, GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE, &translatedSourceLength); |
| |
| if (translatedSourceLength > 0) |
| { |
| std::vector<GLchar> translatedSource(translatedSourceLength); |
| glGetTranslatedShaderSourceANGLE(mShader, translatedSourceLength, nullptr, |
| translatedSource.data()); |
| |
| // Note: the translatedSource is nul-terminated. |
| mTranslatedSource = translatedSource.data(); |
| } |
| } |
| |
| return mShader; |
| } |
| |
| CompiledShader::~CompiledShader() |
| { |
| if (mShader != 0) |
| { |
| destroy(); |
| } |
| } |
| |
| void CompiledShader::destroy() |
| { |
| glDeleteShader(mShader); |
| ASSERT_GL_NO_ERROR(); |
| mShader = 0; |
| |
| mTranslatedSource.clear(); |
| } |
| |
| bool CompiledShader::hasInfoLog(const char *expect) const |
| { |
| return mInfoLog.find(expect) != std::string::npos; |
| } |
| |
| bool CompiledShader::verifyInTranslatedSource(const char *expect) const |
| { |
| return mTranslatedSource.empty() || mTranslatedSource.find(expect) != std::string::npos; |
| } |
| |
| bool CompiledShader::verifyNotInTranslatedSource(const char *expect) const |
| { |
| return mTranslatedSource.empty() || mTranslatedSource.find(expect) == std::string::npos; |
| } |
| |
| bool CompiledShader::verifyCountInTranslatedSource(const char *expect, size_t expectCount) const |
| { |
| if (mTranslatedSource.empty()) |
| { |
| return true; |
| } |
| |
| size_t count = 0; |
| std::string::size_type pos = 0; |
| while (true) |
| { |
| pos = mTranslatedSource.find(expect, pos); |
| if (pos == std::string::npos) |
| { |
| break; |
| } |
| ++count; |
| ++pos; |
| } |
| return count == expectCount; |
| } |
| |
| void CompilerTest::testSetUp() {} |
| |
| void CompilerTest::testTearDown() |
| { |
| reset(); |
| } |
| |
| void CompilerTest::reset() |
| { |
| mVertexShader.destroy(); |
| mTessellationControlShader.destroy(); |
| mTessellationEvaluationShader.destroy(); |
| mGeometryShader.destroy(); |
| mFragmentShader.destroy(); |
| mComputeShader.destroy(); |
| |
| glDeleteProgram(mProgram); |
| mProgram = 0; |
| } |
| |
| const CompiledShader &CompilerTest::compile(GLenum type, const char *source) |
| { |
| CompiledShader &shader = getCompiledShader(type); |
| shader.compile(type, source); |
| return shader; |
| } |
| |
| CompiledShader &CompilerTest::getCompiledShader(GLenum type) |
| { |
| switch (type) |
| { |
| case GL_VERTEX_SHADER: |
| return mVertexShader; |
| case GL_TESS_CONTROL_SHADER: |
| return mTessellationControlShader; |
| case GL_TESS_EVALUATION_SHADER: |
| return mTessellationEvaluationShader; |
| case GL_GEOMETRY_SHADER: |
| return mGeometryShader; |
| case GL_FRAGMENT_SHADER: |
| return mFragmentShader; |
| case GL_COMPUTE_SHADER: |
| return mComputeShader; |
| default: |
| // Unsupported type |
| ASSERT(false); |
| return mVertexShader; |
| } |
| } |
| |
| GLuint CompilerTest::link() |
| { |
| mProgram = glCreateProgram(); |
| |
| if (mComputeShader.success()) |
| { |
| glAttachShader(mProgram, mComputeShader.getShader()); |
| } |
| else |
| { |
| if (mVertexShader.success()) |
| { |
| glAttachShader(mProgram, mVertexShader.getShader()); |
| } |
| if (mTessellationControlShader.success()) |
| { |
| glAttachShader(mProgram, mTessellationControlShader.getShader()); |
| } |
| if (mTessellationEvaluationShader.success()) |
| { |
| glAttachShader(mProgram, mTessellationEvaluationShader.getShader()); |
| } |
| if (mGeometryShader.success()) |
| { |
| glAttachShader(mProgram, mGeometryShader.getShader()); |
| } |
| if (mFragmentShader.success()) |
| { |
| glAttachShader(mProgram, mFragmentShader.getShader()); |
| } |
| } |
| |
| glLinkProgram(mProgram); |
| EXPECT_GL_NO_ERROR(); |
| |
| GLint linkStatus; |
| glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus); |
| EXPECT_NE(linkStatus, 0); |
| |
| return mProgram; |
| } |