/*------------------------------------------------------------------------- * drawElements Quality Program EGL Module * --------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Config query tests. *//*--------------------------------------------------------------------*/ #include "teglQueryConfigTests.hpp" #include "teglSimpleConfigCase.hpp" #include "tcuTestLog.hpp" #include "tcuTestContext.hpp" #include "tcuCommandLine.hpp" #include "egluCallLogWrapper.hpp" #include "egluStrUtil.hpp" #include "egluUtil.hpp" #include "eglwLibrary.hpp" #include "eglwEnums.hpp" #include "deRandom.hpp" #include <string> #include <vector> namespace deqp { namespace egl { using eglu::ConfigInfo; using tcu::TestLog; using namespace eglw; static void logConfigAttribute (TestLog& log, EGLenum attrib, EGLint value) { log << TestLog::Message << " " << eglu::getConfigAttribName(attrib) << ": " << eglu::getConfigAttribValueStr(attrib, value) << TestLog::EndMessage; } static bool isAttributePresent (const eglu::Version& version, EGLenum attribute) { switch (attribute) { case EGL_CONFORMANT: if (version < eglu::Version(1, 3)) return false; break; case EGL_LUMINANCE_SIZE: case EGL_ALPHA_MASK_SIZE: case EGL_COLOR_BUFFER_TYPE: case EGL_MATCH_NATIVE_PIXMAP: if (version < eglu::Version(1, 2)) return false; break; case EGL_BIND_TO_TEXTURE_RGB: case EGL_BIND_TO_TEXTURE_RGBA: case EGL_MAX_SWAP_INTERVAL: case EGL_MIN_SWAP_INTERVAL: case EGL_RENDERABLE_TYPE: if (version < eglu::Version(1, 1)) return false; break; default: break; } return true; } class GetConfigsBoundsCase : public TestCase, protected eglu::CallLogWrapper { public: GetConfigsBoundsCase (EglTestContext& eglTestCtx, const char* name, const char* description) : TestCase (eglTestCtx, name, description) , CallLogWrapper(eglTestCtx.getLibrary(), eglTestCtx.getTestContext().getLog()) , m_display (EGL_NO_DISPLAY) { } void init (void) { DE_ASSERT(m_display == EGL_NO_DISPLAY); m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } void deinit (void) { m_eglTestCtx.getLibrary().terminate(m_display); m_display = EGL_NO_DISPLAY; } void checkGetConfigsBounds (de::Random& rnd, const int numConfigAll, const int numConfigRequested) { tcu::TestLog& log = m_testCtx.getLog(); std::vector<EGLConfig> buffer (numConfigAll + 10); std::vector<deUint32> magicBuffer ((buffer.size() * sizeof(EGLConfig)) / sizeof(deUint32) + 1); const EGLConfig* magicConfigs = reinterpret_cast<EGLConfig*>(&magicBuffer[0]); int numConfigReturned; // Fill buffers with magic for (size_t ndx = 0; ndx < magicBuffer.size(); ndx++) magicBuffer[ndx] = rnd.getUint32(); for (size_t ndx = 0; ndx < buffer.size(); ndx++) buffer[ndx] = magicConfigs[ndx]; eglGetConfigs(m_display, &buffer[0], numConfigRequested, &numConfigReturned); eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); log << TestLog::Message << numConfigReturned << " configs returned" << TestLog::EndMessage; // Compare results with stored magic { int numOverwritten = 0; for (size_t ndx = 0; ndx < buffer.size(); ndx++) { if (buffer[ndx] == magicConfigs[ndx]) { numOverwritten = (int)ndx; break; } } log << TestLog::Message << numOverwritten << " values actually written" << TestLog::EndMessage; if (numConfigReturned > deMax32(numConfigRequested, 0)) { log << TestLog::Message << "Fail, more configs returned than requested." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Too many configs returned"); } if (numOverwritten > deMax32(numConfigReturned, 0)) { log << TestLog::Message << "Fail, buffer overflow detected." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Buffer overflow"); } else if (numOverwritten != numConfigReturned) { log << TestLog::Message << "Fail, reported number of returned configs differs from number of values written." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect size"); } } } IterateResult iterate (void) { tcu::TestLog& log = m_testCtx.getLog(); EGLint numConfigAll; enableLogging(true); eglGetConfigs(m_display, 0, 0, &numConfigAll); log << TestLog::Message << numConfigAll << " configs available" << TestLog::EndMessage; log << TestLog::Message << TestLog::EndMessage; if (numConfigAll > 0) { de::Random rnd (123); for (int i = 0; i < 5; i++) { checkGetConfigsBounds(rnd, numConfigAll, rnd.getInt(0, numConfigAll)); log << TestLog::Message << TestLog::EndMessage; } checkGetConfigsBounds(rnd, numConfigAll, -1); } else { m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "No configs"); } enableLogging(false); return STOP; } protected: EGLDisplay m_display; }; class GetConfigAttribCase : public TestCase, protected eglu::CallLogWrapper { public: GetConfigAttribCase (EglTestContext& eglTestCtx, const char* name, const char* description); void init (void); void deinit (void); IterateResult iterate (void); EGLint getValue (EGLConfig config, EGLenum attrib, bool logValue=true); virtual void executeTest (EGLConfig config) = 0; protected: EGLDisplay m_display; private: std::vector<EGLConfig> m_configs; std::vector<EGLConfig>::const_iterator m_configsIter; }; GetConfigAttribCase::GetConfigAttribCase (EglTestContext& eglTestCtx, const char* name, const char* description) : TestCase (eglTestCtx, name, description) , CallLogWrapper (eglTestCtx.getLibrary(), eglTestCtx.getTestContext().getLog()) , m_display (EGL_NO_DISPLAY) { } void GetConfigAttribCase::init (void) { DE_ASSERT(m_display == EGL_NO_DISPLAY); m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); m_configs = eglu::getConfigs(m_eglTestCtx.getLibrary(), m_display); m_configsIter = m_configs.begin(); m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); } void GetConfigAttribCase::deinit (void) { m_eglTestCtx.getLibrary().terminate(m_display); m_display = EGL_NO_DISPLAY; } tcu::TestNode::IterateResult GetConfigAttribCase::iterate (void) { tcu::TestLog& log = m_testCtx.getLog(); if (m_configsIter == m_configs.end()) { log << TestLog::Message << "No configs available." << TestLog::EndMessage; return STOP; } { const EGLConfig config = *m_configsIter; EGLint id; eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &id); eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); log << TestLog::Message << "Config ID " << id << TestLog::EndMessage; executeTest(config); } log << TestLog::Message << TestLog::EndMessage; m_configsIter++; if (m_configsIter == m_configs.end()) return STOP; else return CONTINUE; } EGLint GetConfigAttribCase::getValue (EGLConfig config, EGLenum attrib, bool logValue) { TestLog& log = m_testCtx.getLog(); EGLint value; eglGetConfigAttrib(m_display, config, attrib, &value); eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); if (logValue) logConfigAttribute(log, attrib, value); return value; } class GetConfigAttribSimpleCase : public GetConfigAttribCase { public: GetConfigAttribSimpleCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLenum attribute) : GetConfigAttribCase(eglTestCtx, name, description) , m_attrib(attribute) { } void checkColorBufferType (EGLint value) { const bool isRGBBuffer = value == EGL_RGB_BUFFER; const bool isLuminanceBuffer = value == EGL_LUMINANCE_BUFFER; const bool isYuvBuffer = value == EGL_YUV_BUFFER_EXT; const bool hasYuvSupport = eglu::hasExtension(m_eglTestCtx.getLibrary(), m_display, "EGL_EXT_yuv_surface"); if (!(isRGBBuffer || isLuminanceBuffer || (isYuvBuffer && hasYuvSupport))) { TestLog& log = m_testCtx.getLog(); log << TestLog::Message << "Fail, invalid EGL_COLOR_BUFFER_TYPE value" << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); } } void checkCaveat (EGLint value) { if (!(value == EGL_NONE || value == EGL_SLOW_CONFIG || value == EGL_NON_CONFORMANT_CONFIG)) { TestLog& log = m_testCtx.getLog(); log << TestLog::Message << "Fail, invalid EGL_CONFIG_CAVEAT value" << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); } } void checkTransparentType (EGLint value) { if (!(value == EGL_NONE || value == EGL_TRANSPARENT_RGB)) { TestLog& log = m_testCtx.getLog(); log << TestLog::Message << "Fail, invalid EGL_TRANSPARENT_TYPE value" << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); } } void checkBoolean (EGLenum attrib, EGLint value) { if (!(value == EGL_FALSE || value == EGL_TRUE)) { TestLog& log = m_testCtx.getLog(); log << TestLog::Message << "Fail, " << eglu::getConfigAttribStr(attrib) << " should be a boolean value." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); } } void checkInteger (EGLenum attrib, EGLint value) { if (attrib == EGL_NATIVE_VISUAL_ID || attrib == EGL_NATIVE_VISUAL_TYPE) // Implementation-defined return; if (attrib == EGL_CONFIG_ID && value < 1) { TestLog& log = m_testCtx.getLog(); log << TestLog::Message << "Fail, config IDs should be positive integer values beginning from 1." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); } } void checkSurfaceTypeMask (EGLint value) { const EGLint wantedBits = EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT; if ((value & wantedBits) == 0) { TestLog& log = m_testCtx.getLog(); log << TestLog::Message << "Fail, config does not actually support creation of any surface type?" << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid value"); } } void checkAttribute (EGLenum attrib, EGLint value) { switch (attrib) { case EGL_COLOR_BUFFER_TYPE: checkColorBufferType(value); break; case EGL_CONFIG_CAVEAT: checkCaveat(value); break; case EGL_TRANSPARENT_TYPE: checkTransparentType(value); break; case EGL_CONFORMANT: case EGL_RENDERABLE_TYPE: // Just print what we know break; case EGL_SURFACE_TYPE: checkSurfaceTypeMask(value); break; case EGL_BIND_TO_TEXTURE_RGB: case EGL_BIND_TO_TEXTURE_RGBA: case EGL_NATIVE_RENDERABLE: checkBoolean(attrib, value); break; default: checkInteger(attrib, value); } } void executeTest (EGLConfig config) { TestLog& log = m_testCtx.getLog(); eglu::Version version = eglu::getVersion(m_eglTestCtx.getLibrary(), m_display); if (!isAttributePresent(version, m_attrib)) { log << TestLog::Message << eglu::getConfigAttribStr(m_attrib) << " not supported by this EGL version"; } else { EGLint value; enableLogging(true); eglGetConfigAttrib(m_display, config, m_attrib, &value); eglu::checkError(eglGetError(), DE_NULL, __FILE__, __LINE__); logConfigAttribute(log, m_attrib, value); checkAttribute(m_attrib, value); enableLogging(false); } } private: EGLenum m_attrib; }; class GetConfigAttribBufferSizeCase : public GetConfigAttribCase { public: GetConfigAttribBufferSizeCase (EglTestContext& eglTestCtx, const char* name, const char* description) : GetConfigAttribCase(eglTestCtx, name, description) { } void executeTest (EGLConfig config) { TestLog& log = m_testCtx.getLog(); const EGLint colorBufferType = getValue(config, EGL_COLOR_BUFFER_TYPE); const EGLint bufferSize = getValue(config, EGL_BUFFER_SIZE); const EGLint redSize = getValue(config, EGL_RED_SIZE); const EGLint greenSize = getValue(config, EGL_GREEN_SIZE); const EGLint blueSize = getValue(config, EGL_BLUE_SIZE); const EGLint luminanceSize = getValue(config, EGL_LUMINANCE_SIZE); const EGLint alphaSize = getValue(config, EGL_ALPHA_SIZE); if (alphaSize < 0) { log << TestLog::Message << "Fail, alpha size must be zero or positive." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid alpha size"); } if (colorBufferType == EGL_RGB_BUFFER) { if (luminanceSize != 0) { log << TestLog::Message << "Fail, luminance size must be zero for an RGB buffer." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid luminance size"); } if (redSize <= 0 || greenSize <= 0 || blueSize <= 0) { log << TestLog::Message << "Fail, RGB component sizes must be positive for an RGB buffer." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid color component size"); } if (bufferSize != (redSize + greenSize + blueSize + alphaSize)) { log << TestLog::Message << "Fail, buffer size must be equal to the sum of RGB component sizes and alpha size." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid buffer size"); } } else if (colorBufferType == EGL_LUMINANCE_BUFFER) { if (luminanceSize <= 0) { log << TestLog::Message << "Fail, luminance size must be positive for a luminance buffer." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid luminance size"); } if (redSize != 0 || greenSize != 0 || blueSize != 0) { log << TestLog::Message << "Fail, RGB component sizes must be zero for a luminance buffer." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid color component size"); } if (bufferSize != (luminanceSize + alphaSize)) { log << TestLog::Message << "Fail, buffer size must be equal to the sum of luminance size and alpha size." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid buffer size"); } } } }; class GetConfigAttribTransparentValueCase : public GetConfigAttribCase { public: GetConfigAttribTransparentValueCase (EglTestContext& eglTestCtx, const char* name, const char* description) : GetConfigAttribCase(eglTestCtx, name, description) { } void executeTest (EGLConfig config) { TestLog& log = m_testCtx.getLog(); const EGLint transparentType = getValue(config, EGL_TRANSPARENT_TYPE); const EGLint redValue = getValue(config, EGL_TRANSPARENT_RED_VALUE); const EGLint greenValue = getValue(config, EGL_TRANSPARENT_GREEN_VALUE); const EGLint blueValue = getValue(config, EGL_TRANSPARENT_BLUE_VALUE); const EGLint redSize = getValue(config, EGL_RED_SIZE); const EGLint greenSize = getValue(config, EGL_GREEN_SIZE); const EGLint blueSize = getValue(config, EGL_BLUE_SIZE); if (transparentType == EGL_TRANSPARENT_RGB) { if ( (redValue < 0 || redValue >= (1 << redSize)) || (greenValue < 0 || greenValue >= (1 << greenSize)) || (blueValue < 0 || blueValue >= (1 << blueSize)) ) { log << TestLog::Message << "Fail, transparent color values must lie between 0 and the maximum component value." << TestLog::EndMessage; m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid transparent color value"); } } } }; QueryConfigTests::QueryConfigTests (EglTestContext& eglTestCtx) : TestCaseGroup(eglTestCtx, "query_config", "Surface config query tests") { } QueryConfigTests::~QueryConfigTests (void) { } void QueryConfigTests::init (void) { // eglGetGonfigs { tcu::TestCaseGroup* getConfigsGroup = new tcu::TestCaseGroup(m_testCtx, "get_configs", "eglGetConfigs tests"); addChild(getConfigsGroup); getConfigsGroup->addChild(new GetConfigsBoundsCase(m_eglTestCtx, "get_configs_bounds", "eglGetConfigs bounds checking test")); } // eglGetConfigAttrib { static const struct { EGLenum attribute; const char* testName; } attributes[] = { { EGL_BUFFER_SIZE, "buffer_size" }, { EGL_RED_SIZE, "red_size" }, { EGL_GREEN_SIZE, "green_size" }, { EGL_BLUE_SIZE, "blue_size" }, { EGL_LUMINANCE_SIZE, "luminance_size" }, { EGL_ALPHA_SIZE, "alpha_size" }, { EGL_ALPHA_MASK_SIZE, "alpha_mask_size" }, { EGL_BIND_TO_TEXTURE_RGB, "bind_to_texture_rgb" }, { EGL_BIND_TO_TEXTURE_RGBA, "bind_to_texture_rgba" }, { EGL_COLOR_BUFFER_TYPE, "color_buffer_type" }, { EGL_CONFIG_CAVEAT, "config_caveat" }, { EGL_CONFIG_ID, "config_id" }, { EGL_CONFORMANT, "conformant" }, { EGL_DEPTH_SIZE, "depth_size" }, { EGL_LEVEL, "level" }, { EGL_MAX_SWAP_INTERVAL, "max_swap_interval" }, { EGL_MIN_SWAP_INTERVAL, "min_swap_interval" }, { EGL_NATIVE_RENDERABLE, "native_renderable" }, { EGL_NATIVE_VISUAL_TYPE, "native_visual_type" }, { EGL_RENDERABLE_TYPE, "renderable_type" }, { EGL_SAMPLE_BUFFERS, "sample_buffers" }, { EGL_SAMPLES, "samples" }, { EGL_STENCIL_SIZE, "stencil_size" }, { EGL_SURFACE_TYPE, "surface_type" }, { EGL_TRANSPARENT_TYPE, "transparent_type" }, { EGL_TRANSPARENT_RED_VALUE, "transparent_red_value" }, { EGL_TRANSPARENT_GREEN_VALUE, "transparent_green_value" }, { EGL_TRANSPARENT_BLUE_VALUE, "transparent_blue_value" } }; tcu::TestCaseGroup* simpleGroup = new tcu::TestCaseGroup(m_testCtx, "get_config_attrib", "eglGetConfigAttrib() tests"); addChild(simpleGroup); for (int ndx = 0; ndx < (int)DE_LENGTH_OF_ARRAY(attributes); ndx++) { simpleGroup->addChild(new GetConfigAttribSimpleCase(m_eglTestCtx, attributes[ndx].testName, "Simple attribute query case", attributes[ndx].attribute)); } } // Attribute constraints { tcu::TestCaseGroup* constraintsGroup = new tcu::TestCaseGroup(m_testCtx, "constraints", "Attribute constraint tests"); addChild(constraintsGroup); constraintsGroup->addChild(new GetConfigAttribBufferSizeCase(m_eglTestCtx, "color_buffer_size", "Color buffer component sizes")); constraintsGroup->addChild(new GetConfigAttribTransparentValueCase(m_eglTestCtx, "transparent_value", "Transparent color value")); } } } // egl } // deqp