| // | |
| // 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()) << "\n"; | |
| 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; | |
| } |