/*------------------------------------------------------------------------- * 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 EGL image tests. *//*--------------------------------------------------------------------*/ #include "teglImageFormatTests.hpp" #include "tcuTestLog.hpp" #include "tcuSurface.hpp" #include "tcuTexture.hpp" #include "tcuTextureUtil.hpp" #include "tcuImageCompare.hpp" #include "tcuCommandLine.hpp" #include "egluNativeDisplay.hpp" #include "egluNativeWindow.hpp" #include "egluNativePixmap.hpp" #include "egluConfigFilter.hpp" #include "egluUtil.hpp" #include "gluTexture.hpp" #include "gluPixelTransfer.hpp" #include "gluTextureUtil.hpp" #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <EGL/eglext.h> #include <vector> #include <string> #include <set> using std::vector; using std::set; using std::string; namespace deqp { namespace egl { namespace { // \todo [2013-04-09 pyry] Use glu::Program class Program { public: Program (const char* vertexSource, const char* fragmentSource) : m_program (0) , m_vertexShader (0) , m_fragmentShader (0) , m_isOk (false) { m_program = glCreateProgram(); m_vertexShader = glCreateShader(GL_VERTEX_SHADER); m_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); try { bool vertexCompileOk = false; bool fragmentCompileOk = false; bool linkOk = false; for (int ndx = 0; ndx < 2; ndx++) { const char* source = ndx ? fragmentSource : vertexSource; const deUint32 shader = ndx ? m_fragmentShader : m_vertexShader; int compileStatus = 0; bool& compileOk = ndx ? fragmentCompileOk : vertexCompileOk; glShaderSource(shader, 1, &source, DE_NULL); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); compileOk = (compileStatus == GL_TRUE); } if (vertexCompileOk && fragmentCompileOk) { int linkStatus = 0; glAttachShader(m_program, m_vertexShader); glAttachShader(m_program, m_fragmentShader); glLinkProgram(m_program); glGetProgramiv(m_program, GL_LINK_STATUS, &linkStatus); linkOk = (linkStatus == GL_TRUE); } m_isOk = linkOk; } catch (...) { glDeleteShader(m_vertexShader); glDeleteShader(m_fragmentShader); glDeleteProgram(m_program); throw; } } ~Program (void) { glDeleteShader(m_vertexShader); glDeleteShader(m_fragmentShader); glDeleteProgram(m_program); } bool isOk (void) const { return m_isOk; } deUint32 getProgram (void) const {return m_program; } private: deUint32 m_program; deUint32 m_vertexShader; deUint32 m_fragmentShader; bool m_isOk; }; } // anonymous namespace Image { class EglExt { public: EglExt (void) { eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); glEGLImageTargetRenderbufferStorageOES = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES"); } PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES; private: }; struct TestSpec { std::string name; std::string desc; enum ApiContext { API_GLES2 = 0, //API_VG //API_GLES1 API_LAST }; struct Operation { enum Type { TYPE_CREATE = 0, TYPE_RENDER, TYPE_MODIFY, TYPE_LAST }; ApiContext requiredApi; int apiIndex; Type type; int operationIndex; }; vector<ApiContext> contexts; vector<Operation> operations; }; class ImageApi { public: ImageApi (int contextId, tcu::TestLog& log, tcu::egl::Display& display, tcu::egl::Surface* surface); virtual ~ImageApi (void) {} virtual EGLImageKHR create (int operationNdx, tcu::Texture2D& ref) = 0; virtual bool render (int operationNdx, EGLImageKHR img, const tcu::Texture2D& reference) = 0; virtual void modify (int operationNdx, EGLImageKHR img, tcu::Texture2D& reference) = 0; virtual void checkRequiredExtensions (set<string>& extensions, TestSpec::Operation::Type type, int operationNdx) = 0; protected: int m_contextId; tcu::TestLog& m_log; tcu::egl::Display& m_display; tcu::egl::Surface* m_surface; }; ImageApi::ImageApi (int contextId, tcu::TestLog& log, tcu::egl::Display& display, tcu::egl::Surface* surface) : m_contextId (contextId) , m_log (log) , m_display (display) , m_surface (surface) { } class GLES2ImageApi : public ImageApi { public: enum Create { CREATE_TEXTURE2D_RGB8 = 0, CREATE_TEXTURE2D_RGB565, CREATE_TEXTURE2D_RGBA8, CREATE_TEXTURE2D_RGBA5_A1, CREATE_TEXTURE2D_RGBA4, CREATE_CUBE_MAP_POSITIVE_X_RGBA8, CREATE_CUBE_MAP_NEGATIVE_X_RGBA8, CREATE_CUBE_MAP_POSITIVE_Y_RGBA8, CREATE_CUBE_MAP_NEGATIVE_Y_RGBA8, CREATE_CUBE_MAP_POSITIVE_Z_RGBA8, CREATE_CUBE_MAP_NEGATIVE_Z_RGBA8, CREATE_CUBE_MAP_POSITIVE_X_RGB8, CREATE_CUBE_MAP_NEGATIVE_X_RGB8, CREATE_CUBE_MAP_POSITIVE_Y_RGB8, CREATE_CUBE_MAP_NEGATIVE_Y_RGB8, CREATE_CUBE_MAP_POSITIVE_Z_RGB8, CREATE_CUBE_MAP_NEGATIVE_Z_RGB8, CREATE_RENDER_BUFFER_DEPTH16, CREATE_RENDER_BUFFER_RGBA4, CREATE_RENDER_BUFFER_RGB5_A1, CREATE_RENDER_BUFFER_RGB565, CREATE_RENDER_BUFFER_STENCIL, CREATE_LAST }; enum Render { RENDER_TEXTURE2D = 0, // \note Not supported RENDER_CUBE_MAP_POSITIVE_X, RENDER_CUBE_MAP_NEGATIVE_X, RENDER_CUBE_MAP_POSITIVE_Y, RENDER_CUBE_MAP_NEGATIVE_Y, RENDER_CUBE_MAP_POSITIVE_Z, RENDER_CUBE_MAP_NEGATIVE_Z, RENDER_READ_PIXELS_RENDERBUFFER, RENDER_DEPTHBUFFER, RENDER_TRY_ALL, RENDER_LAST }; enum Modify { MODIFY_TEXSUBIMAGE_RGBA8, MODIFY_TEXSUBIMAGE_RGBA5_A1, MODIFY_TEXSUBIMAGE_RGBA4, MODIFY_TEXSUBIMAGE_RGB8, MODIFY_TEXSUBIMAGE_RGB565, MODIFY_RENDERBUFFER_CLEAR_COLOR, MODIFY_RENDERBUFFER_CLEAR_DEPTH, MODIFY_RENDERBUFFER_CLEAR_STENCIL, MODIFY_LAST }; GLES2ImageApi (int contextId, tcu::TestLog& log, tcu::egl::Display& display, tcu::egl::Surface* surface, EGLConfig config); ~GLES2ImageApi (void); EGLImageKHR create (int operationNdx, tcu::Texture2D& ref); EGLImageKHR createTexture2D (tcu::Texture2D& ref, GLenum target, GLenum format, GLenum type); EGLImageKHR createRenderBuffer (tcu::Texture2D& ref, GLenum type); bool render (int operationNdx, EGLImageKHR img, const tcu::Texture2D& reference); bool renderTexture2D (EGLImageKHR img, const tcu::Texture2D& reference); bool renderDepth (EGLImageKHR img, const tcu::Texture2D& reference); bool renderReadPixelsRenderBuffer (EGLImageKHR img, const tcu::Texture2D& reference); bool renderTryAll (EGLImageKHR img, const tcu::Texture2D& reference); // \note Not supported bool renderCubeMap (EGLImageKHR img, const tcu::Surface& reference, GLenum face); void modify (int operationNdx, EGLImageKHR img, tcu::Texture2D& reference); void modifyTexSubImage (EGLImageKHR img, tcu::Texture2D& reference, GLenum format, GLenum type); void modifyRenderbufferClearColor (EGLImageKHR img, tcu::Texture2D& reference); void modifyRenderbufferClearDepth (EGLImageKHR img, tcu::Texture2D& reference); void modifyRenderbufferClearStencil (EGLImageKHR img, tcu::Texture2D& reference); void checkRequiredExtensions (set<string>& extensions, TestSpec::Operation::Type type, int operationNdx); private: tcu::egl::Context* m_context; EglExt m_eglExt; }; GLES2ImageApi::GLES2ImageApi (int contextId, tcu::TestLog& log, tcu::egl::Display& display, tcu::egl::Surface* surface, EGLConfig config) : ImageApi (contextId, log, display, surface) , m_context (DE_NULL) { EGLint attriblist[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint configId = -1; TCU_CHECK_EGL_CALL(eglGetConfigAttrib(m_display.getEGLDisplay(), config, EGL_CONFIG_ID, &configId)); m_log << tcu::TestLog::Message << "Creating gles2 context with config id: " << configId << " context: " << m_contextId << tcu::TestLog::EndMessage; m_context = new tcu::egl::Context(m_display, config, attriblist, EGL_OPENGL_ES_API); TCU_CHECK_EGL_MSG("Failed to create GLES2 context"); m_context->makeCurrent(*m_surface, *m_surface); TCU_CHECK_EGL_MSG("Failed to make context current"); } GLES2ImageApi::~GLES2ImageApi (void) { delete m_context; } EGLImageKHR GLES2ImageApi::create (int operationNdx, tcu::Texture2D& ref) { m_context->makeCurrent(*m_surface, *m_surface); EGLImageKHR img = EGL_NO_IMAGE_KHR; switch (operationNdx) { case CREATE_TEXTURE2D_RGB8: img = createTexture2D(ref, GL_TEXTURE_2D, GL_RGB, GL_UNSIGNED_BYTE); break; case CREATE_TEXTURE2D_RGB565: img = createTexture2D(ref, GL_TEXTURE_2D, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); break; case CREATE_TEXTURE2D_RGBA8: img = createTexture2D(ref, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_BYTE); break; case CREATE_TEXTURE2D_RGBA4: img = createTexture2D(ref, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4); break; case CREATE_TEXTURE2D_RGBA5_A1: img = createTexture2D(ref, GL_TEXTURE_2D, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1); break; case CREATE_CUBE_MAP_POSITIVE_X_RGBA8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_RGBA, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_NEGATIVE_X_RGBA8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_RGBA, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_POSITIVE_Y_RGBA8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_RGBA, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_NEGATIVE_Y_RGBA8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_RGBA, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_POSITIVE_Z_RGBA8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_RGBA, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_NEGATIVE_Z_RGBA8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_RGBA, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_POSITIVE_X_RGB8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_RGB, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_NEGATIVE_X_RGB8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_RGB, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_POSITIVE_Y_RGB8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_RGB, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_NEGATIVE_Y_RGB8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_RGB, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_POSITIVE_Z_RGB8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_RGB, GL_UNSIGNED_BYTE); break; case CREATE_CUBE_MAP_NEGATIVE_Z_RGB8: img = createTexture2D(ref, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_RGB, GL_UNSIGNED_BYTE); break; case CREATE_RENDER_BUFFER_DEPTH16: img = createRenderBuffer(ref, GL_DEPTH_COMPONENT16); break; case CREATE_RENDER_BUFFER_RGBA4: img = createRenderBuffer(ref, GL_RGBA4); break; case CREATE_RENDER_BUFFER_RGB5_A1: img = createRenderBuffer(ref, GL_RGB5_A1); break; case CREATE_RENDER_BUFFER_RGB565: img = createRenderBuffer(ref, GL_RGB565); break; case CREATE_RENDER_BUFFER_STENCIL: img = createRenderBuffer(ref, GL_STENCIL_INDEX8); break; default: DE_ASSERT(false); break; } return img; } namespace { const char* glTargetToString (GLenum target) { switch (target) { case GL_TEXTURE_2D: return "GL_TEXTURE_2D"; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_X: return "GL_TEXTURE_CUBE_MAP_POSITIVE_X"; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_X"; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Y"; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Y"; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: return "GL_TEXTURE_CUBE_MAP_POSITIVE_Z"; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z"; break; default: DE_ASSERT(false); break; }; return ""; } const char* glFormatToString (GLenum format) { switch (format) { case GL_RGB: return "GL_RGB"; case GL_RGBA: return "GL_RGBA"; default: DE_ASSERT(false); return ""; } } const char* glTypeToString (GLenum type) { switch (type) { case GL_UNSIGNED_BYTE: return "GL_UNSIGNED_BYTE"; case GL_UNSIGNED_SHORT_5_6_5: return "GL_UNSIGNED_SHORT_5_6_5"; case GL_UNSIGNED_SHORT_4_4_4_4: return "GL_UNSIGNED_SHORT_4_4_4_4"; case GL_UNSIGNED_SHORT_5_5_5_1: return "GL_UNSIGNED_SHORT_5_5_5_1"; default: DE_ASSERT(false); return ""; } } } // anonymous EGLImageKHR GLES2ImageApi::createTexture2D (tcu::Texture2D& reference, GLenum target, GLenum format, GLenum type) { tcu::Texture2D src(glu::mapGLTransferFormat(format, type), 64, 64); src.allocLevel(0); tcu::fillWithComponentGradients(src.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); m_log << tcu::TestLog::Message << "Creating EGLImage from " << glTargetToString(target) << " " << glFormatToString(format) << " " << glTypeToString(type) << " in context: " << m_contextId << tcu::TestLog::EndMessage; deUint32 srcTex = 0; glGenTextures(1, &srcTex); TCU_CHECK(srcTex != 0); if (GL_TEXTURE_2D == target) { GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, srcTex)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_2D, 0, format, src.getWidth(), src.getHeight(), 0, format, type, src.getLevel(0).getDataPtr())); } else { GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, srcTex)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); // First fill all faces, required by eglCreateImageKHR GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format, src.getWidth(), src.getHeight(), 0, format, type, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format, src.getWidth(), src.getHeight(), 0, format, type, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format, src.getWidth(), src.getHeight(), 0, format, type, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format, src.getWidth(), src.getHeight(), 0, format, type, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format, src.getWidth(), src.getHeight(), 0, format, type, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format, src.getWidth(), src.getHeight(), 0, format, type, 0)); GLU_CHECK_CALL(glTexImage2D(target, 0, format, src.getWidth(), src.getHeight(), 0, format, type, src.getLevel(0).getDataPtr())); } EGLint attrib[] = { EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE }; EGLImageKHR img = EGL_NO_IMAGE_KHR; if (GL_TEXTURE_2D == target) { img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(deUintptr)srcTex, attrib); } else { switch (target) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, (EGLClientBuffer)(deUintptr)srcTex, attrib); break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR, (EGLClientBuffer)(deUintptr)srcTex, attrib); break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR, (EGLClientBuffer)(deUintptr)srcTex, attrib); break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR, (EGLClientBuffer)(deUintptr)srcTex, attrib); break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR, (EGLClientBuffer)(deUintptr)srcTex, attrib); break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR, (EGLClientBuffer)(deUintptr)srcTex, attrib); break; default: DE_ASSERT(false); break; } } GLU_CHECK_CALL(glDeleteTextures(1, &srcTex)); TCU_CHECK_EGL_MSG("Failed to create EGLImage"); TCU_CHECK_MSG(img != EGL_NO_IMAGE_KHR, "Failed to create EGLImage, got EGL_NO_IMAGE_KHR"); glBindTexture(GL_TEXTURE_2D, 0); reference = src; return img; } static std::string glRenderbufferTargetToString (GLenum format) { switch (format) { case GL_RGBA4: return "GL_RGBA4"; break; case GL_RGB5_A1: return "GL_RGB5_A1"; break; case GL_RGB565: return "GL_RGB565"; break; case GL_DEPTH_COMPONENT16: return "GL_DEPTH_COMPONENT16"; break; case GL_STENCIL_INDEX8: return "GL_STENCIL_INDEX8"; break; default: DE_ASSERT(false); break; } DE_ASSERT(false); return ""; } EGLImageKHR GLES2ImageApi::createRenderBuffer (tcu::Texture2D& ref, GLenum format) { m_log << tcu::TestLog::Message << "Creating EGLImage from GL_RENDERBUFFER " << glRenderbufferTargetToString(format) << " " << " in context: " << m_contextId << tcu::TestLog::EndMessage; GLuint renderBuffer = 1; GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer)); GLU_CHECK_CALL(glRenderbufferStorage(GL_RENDERBUFFER, format, 64, 64)); GLuint frameBuffer = 1; GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer)); switch (format) { case GL_STENCIL_INDEX8: GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer)); TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); GLU_CHECK_CALL(glClearStencil(235)); GLU_CHECK_CALL(glClear(GL_STENCIL_BUFFER_BIT)); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0)); ref = tcu::Texture2D(tcu::TextureFormat(tcu::TextureFormat::I, tcu::TextureFormat::UNORM_INT8), 64, 64); ref.allocLevel(0); for (int x = 0; x < 64; x++) { for (int y = 0; y < 64; y++) { ref.getLevel(0).setPixel(tcu::IVec4(235, 235, 235, 235), x, y); } } break; case GL_DEPTH_COMPONENT16: GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffer)); TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); GLU_CHECK_CALL(glClearDepthf(0.5f)); GLU_CHECK_CALL(glClear(GL_DEPTH_BUFFER_BIT)); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0)); ref = tcu::Texture2D(tcu::TextureFormat(tcu::TextureFormat::I, tcu::TextureFormat::UNORM_INT16), 64, 64); ref.allocLevel(0); for (int x = 0; x < 64; x++) { for (int y = 0; y < 64; y++) { ref.getLevel(0).setPixel(tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f), x, y); } } break; case GL_RGBA4: GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer)); TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); GLU_CHECK_CALL(glClearColor(0.9f, 0.5f, 0.65f, 1.0f)); GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT)); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0)); ref = tcu::Texture2D(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_SHORT_4444), 64, 64); ref.allocLevel(0); for (int x = 0; x < 64; x++) { for (int y = 0; y < 64; y++) { ref.getLevel(0).setPixel(tcu::Vec4(0.9f, 0.5f, 0.65f, 1.0f), x, y); } } break; case GL_RGB5_A1: GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer)); TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); GLU_CHECK_CALL(glClearColor(0.5f, 0.7f, 0.65f, 1.0f)); GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT)); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0)); ref = tcu::Texture2D(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_SHORT_5551), 64, 64); ref.allocLevel(0); for (int x = 0; x < 64; x++) { for (int y = 0; y < 64; y++) { ref.getLevel(0).setPixel(tcu::Vec4(0.5f, 0.7f, 0.65f, 1.0f), x, y); } } break; case GL_RGB565: GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer)); TCU_CHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); GLU_CHECK_CALL(glClearColor(0.2f, 0.5f, 0.65f, 1.0f)); GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT)); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0)); ref = tcu::Texture2D(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_SHORT_565), 64, 64); ref.allocLevel(0); for (int x = 0; x < 64; x++) { for (int y = 0; y < 64; y++) { ref.getLevel(0).setPixel(tcu::Vec4(0.2f, 0.5f, 0.65f, 1.0f), x, y); } } break; default: DE_ASSERT(false); } GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GLU_CHECK_CALL(glDeleteFramebuffers(1, &frameBuffer)); EGLint attrib[] = { EGL_NONE }; EGLImageKHR img = m_eglExt.eglCreateImageKHR(m_display.getEGLDisplay(), m_context->getEGLContext(), EGL_GL_RENDERBUFFER_KHR, (EGLClientBuffer)(deUintptr)renderBuffer, attrib); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderBuffer)); return img; } bool GLES2ImageApi::render (int operationNdx, EGLImageKHR img, const tcu::Texture2D& reference) { m_context->makeCurrent(*m_surface, *m_surface); switch (operationNdx) { case RENDER_TEXTURE2D: return renderTexture2D(img, reference); case RENDER_READ_PIXELS_RENDERBUFFER: return renderReadPixelsRenderBuffer(img, reference); case RENDER_DEPTHBUFFER: return renderDepth(img, reference); case RENDER_TRY_ALL: return renderTryAll(img, reference); default: DE_ASSERT(false); break; }; return false; } bool GLES2ImageApi::renderTexture2D (EGLImageKHR img, const tcu::Texture2D& reference) { glClearColor(0.0, 0.0, 0.0, 0.0); glViewport(0, 0, reference.getWidth(), reference.getHeight()); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glDisable(GL_DEPTH_TEST); m_log << tcu::TestLog::Message << "Rendering EGLImage as GL_TEXTURE_2D in context: " << m_contextId << tcu::TestLog::EndMessage; TCU_CHECK(img != EGL_NO_IMAGE_KHR); deUint32 srcTex = 0; glGenTextures(1, &srcTex); TCU_CHECK(srcTex != 0); GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, srcTex)); m_eglExt.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteTextures(1, &srcTex)); throw tcu::NotSupportedError("Creating texture2D from EGLImage type not supported", "glEGLImageTargetTexture2DOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetTexture2DOES() failed"); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); const char* vertexShader = "attribute highp vec2 a_coord;\n" "varying mediump vec2 v_texCoord;\n" "void main(void) {\n" "\tv_texCoord = vec2((a_coord.x + 1.0) * 0.5, (a_coord.y + 1.0) * 0.5);\n" "\tgl_Position = vec4(a_coord, -0.1, 1.0);\n" "}\n"; const char* fragmentShader = "varying mediump vec2 v_texCoord;\n" "uniform sampler2D u_sampler;\n" "void main(void) {\n" "\tmediump vec4 texColor = texture2D(u_sampler, v_texCoord);\n" "\tgl_FragColor = vec4(texColor);\n" "}"; Program program(vertexShader, fragmentShader); TCU_CHECK(program.isOk()); GLuint glProgram = program.getProgram(); GLU_CHECK_CALL(glUseProgram(glProgram)); GLuint coordLoc = glGetAttribLocation(glProgram, "a_coord"); TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); GLuint samplerLoc = glGetUniformLocation(glProgram, "u_sampler"); TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform u_sampler"); float coords[] = { -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0 }; GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, srcTex)); GLU_CHECK_CALL(glUniform1i(samplerLoc, 0)); GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc)); GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords)); GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 6)); GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc)); GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, 0)); GLU_CHECK_CALL(glDeleteTextures(1, &srcTex)); tcu::Surface screen(reference.getWidth(), reference.getHeight()); glReadPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr()); GLU_CHECK_MSG("glReadPixels()"); tcu::Surface referenceScreen(reference.getWidth(), reference.getHeight()); for (int y = 0; y < referenceScreen.getHeight(); y++) { for (int x = 0; x < referenceScreen.getWidth(); x++) { tcu::Vec4 src = reference.getLevel(0).getPixel(x, y); referenceScreen.setPixel(x, y, tcu::RGBA(src)); } } float threshold = 0.05f; bool match = tcu::fuzzyCompare(m_log, "ComparisonResult", "Image comparison result", referenceScreen, screen, threshold, tcu::COMPARE_LOG_RESULT); return match; } bool GLES2ImageApi::renderDepth (EGLImageKHR img, const tcu::Texture2D& reference) { m_log << tcu::TestLog::Message << "Rendering with depth buffer" << tcu::TestLog::EndMessage; deUint32 framebuffer; glGenFramebuffers(1, &framebuffer); TCU_CHECK(framebuffer != (GLuint)-1); GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer)); deUint32 renderbufferColor = 0; glGenRenderbuffers(1, &renderbufferColor); TCU_CHECK(renderbufferColor != (GLuint)-1); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbufferColor)); GLU_CHECK_CALL(glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, reference.getWidth(), reference.getHeight())); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); deUint32 renderbufferDepth = 0; glGenRenderbuffers(1, &renderbufferDepth); TCU_CHECK(renderbufferDepth != (GLuint)-1); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbufferDepth)); m_eglExt.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbufferDepth)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbufferColor)); throw tcu::NotSupportedError("Creating renderbuffer from EGLImage type not supported", "glEGLImageTargetRenderbufferStorageOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetRenderbufferStorageOES() failed"); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbufferDepth)); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbufferDepth)); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbufferColor)); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbufferColor)); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); GLU_CHECK_CALL(glViewport(0, 0, reference.getWidth(), reference.getHeight())); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbufferDepth)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbufferColor)); throw tcu::NotSupportedError("EGLImage as depth attachment not supported", "", __FILE__, __LINE__); } // Render const char* vertexShader = "attribute highp vec2 a_coord;\n" "uniform highp float u_depth;\n" "void main(void) {\n" "\tgl_Position = vec4(a_coord, u_depth, 1.0);\n" "}\n"; const char* fragmentShader = "uniform mediump vec4 u_color;\n" "void main(void) {\n" "\tgl_FragColor = u_color;\n" "}"; Program program(vertexShader, fragmentShader); TCU_CHECK(program.isOk()); GLuint glProgram = program.getProgram(); GLU_CHECK_CALL(glUseProgram(glProgram)); GLuint coordLoc = glGetAttribLocation(glProgram, "a_coord"); TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); GLuint colorLoc = glGetUniformLocation(glProgram, "u_color"); TCU_CHECK_MSG((int)colorLoc != (int)-1, "Couldn't find uniform u_color"); GLuint depthLoc = glGetUniformLocation(glProgram, "u_depth"); TCU_CHECK_MSG((int)depthLoc != (int)-1, "Couldn't find uniform u_depth"); float coords[] = { -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0 }; float depthLevels[] = { 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f }; tcu::Vec4 depthLevelColors[] = { tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), tcu::Vec4(0.5f, 0.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 0.5f, 0.0f, 1.0f), tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f) }; DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(depthLevels) == DE_LENGTH_OF_ARRAY(depthLevelColors)); GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc)); GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords)); GLU_CHECK_CALL(glEnable(GL_DEPTH_TEST)); GLU_CHECK_CALL(glDepthFunc(GL_LESS)); for (int level = 0; level < DE_LENGTH_OF_ARRAY(depthLevels); level++) { tcu::Vec4 color = depthLevelColors[level]; GLU_CHECK_CALL(glUniform4f(colorLoc, color.x(), color.y(), color.z(), color.w())); GLU_CHECK_CALL(glUniform1f(depthLoc, depthLevels[level])); GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 6)); } GLU_CHECK_CALL(glDisable(GL_DEPTH_TEST)); GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc)); tcu::Surface screen(reference.getWidth(), reference.getHeight()); tcu::Surface referenceScreen(reference.getWidth(), reference.getHeight()); glReadPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr()); for (int y = 0; y < reference.getHeight(); y++) { for (int x = 0; x < reference.getWidth(); x++) { tcu::RGBA result; for (int level = 0; level < DE_LENGTH_OF_ARRAY(depthLevels); level++) { tcu::Vec4 src = reference.getLevel(0).getPixel(x, y); if (src.x() < depthLevels[level]) { result = tcu::RGBA((int)(depthLevelColors[level].x() * 255.0f), (int)(depthLevelColors[level].y() * 255.0f), (int)(depthLevelColors[level].z() * 255.0f), (int)(depthLevelColors[level].w() * 255.0f)); } } referenceScreen.setPixel(x, reference.getHeight(), result); } } bool isOk = tcu::pixelThresholdCompare(m_log, "Depth buffer rendering result", "Result from rendering with depth buffer", referenceScreen, screen, tcu::RGBA(1,1,1,1), tcu::COMPARE_LOG_RESULT); GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbufferDepth)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbufferColor)); GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glFinish()); return isOk; } bool GLES2ImageApi::renderReadPixelsRenderBuffer (EGLImageKHR img, const tcu::Texture2D& reference) { m_log << tcu::TestLog::Message << "Reading with ReadPixels from renderbuffer" << tcu::TestLog::EndMessage; deUint32 framebuffer; glGenFramebuffers(1, &framebuffer); TCU_CHECK(framebuffer != (GLuint)-1); GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer)); deUint32 renderbuffer = 0; glGenRenderbuffers(1, &renderbuffer); TCU_CHECK(renderbuffer != (GLuint)-1); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer)); m_eglExt.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("Creating renderbuffer from EGLImage type not supported", "glEGLImageTargetRenderbufferStorageOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetRenderbufferStorageOES() failed"); GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer)); GLU_CHECK_CALL(glViewport(0, 0, reference.getWidth(), reference.getHeight())); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("EGLImage as color attachment not supported", "", __FILE__, __LINE__); } tcu::Surface screen(reference.getWidth(), reference.getHeight()); tcu::Surface referenceScreen(reference.getWidth(), reference.getHeight()); glReadPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr()); for (int y = 0; y < reference.getHeight(); y++) { for (int x = 0; x < reference.getWidth(); x++) { tcu::Vec4 src = reference.getLevel(0).getPixel(x, y); referenceScreen.setPixel(x, y, tcu::RGBA(src)); } } bool isOk = tcu::pixelThresholdCompare(m_log, "Renderbuffer read", "Result from reading renderbuffer", referenceScreen, screen, tcu::RGBA(1,1,1,1), tcu::COMPARE_LOG_RESULT); GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glFinish()); return isOk; } bool GLES2ImageApi::renderTryAll (EGLImageKHR img, const tcu::Texture2D& reference) { bool isOk = true; bool foundSupportedRendering = false; try { if (!renderTexture2D(img, reference)) isOk = false; foundSupportedRendering = true; } catch (const tcu::NotSupportedError& error) { m_log << tcu::TestLog::Message << error.what() << tcu::TestLog::EndMessage; } if (!isOk) return false; try { if (!renderReadPixelsRenderBuffer(img, reference)) isOk = false; foundSupportedRendering = true; } catch (const tcu::NotSupportedError& error) { m_log << tcu::TestLog::Message << error.what() << tcu::TestLog::EndMessage; } if (!isOk) return false; try { if (!renderDepth(img, reference)) isOk = false; foundSupportedRendering = true; } catch (const tcu::NotSupportedError& error) { m_log << tcu::TestLog::Message << error.what() << tcu::TestLog::EndMessage; } if (!foundSupportedRendering) throw tcu::NotSupportedError("Rendering not supported", "", __FILE__, __LINE__); return isOk; } bool GLES2ImageApi::renderCubeMap (EGLImageKHR img, const tcu::Surface& reference, GLenum face) { // \note This is not supported by EGLImage DE_ASSERT(false); glClearColor(0.5, 0.5, 0.5, 1.0); glViewport(0, 0, reference.getWidth(), reference.getHeight()); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glDisable(GL_DEPTH_TEST); m_log << tcu::TestLog::Message << "Rendering EGLImage as " << glTargetToString(face) << " in context: " << m_contextId << tcu::TestLog::EndMessage; DE_ASSERT(img != EGL_NO_IMAGE_KHR); deUint32 srcTex = 0; glGenTextures(1, &srcTex); DE_ASSERT(srcTex != 0); GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, srcTex)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, reference.getWidth(), reference.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, reference.getWidth(), reference.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, reference.getWidth(), reference.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, reference.getWidth(), reference.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, reference.getWidth(), reference.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, reference.getWidth(), reference.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); m_eglExt.glEGLImageTargetTexture2DOES(face, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteTextures(1, &srcTex)); throw tcu::NotSupportedError("Creating texture cubemap from EGLImage type not supported", "glEGLImageTargetTexture2DOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetTexture2DOES() failed"); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); const char* vertexShader = "attribute highp vec3 a_coord;\n" "attribute highp vec3 a_texCoord;\n" "varying mediump vec3 v_texCoord;\n" "void main(void) {\n" "\tv_texCoord = a_texCoord;\n" "\tgl_Position = vec4(a_coord.xy, -0.1, 1.0);\n" "}\n"; const char* fragmentShader = "varying mediump vec3 v_texCoord;\n" "uniform samplerCube u_sampler;\n" "void main(void) {\n" "\tmediump vec4 texColor = textureCube(u_sampler, v_texCoord);\n" "\tgl_FragColor = vec4(texColor.rgb, 1.0);\n" "}"; Program program(vertexShader, fragmentShader); DE_ASSERT(program.isOk()); GLuint glProgram = program.getProgram(); GLU_CHECK_CALL(glUseProgram(glProgram)); GLint coordLoc = glGetAttribLocation(glProgram, "a_coord"); DE_ASSERT(coordLoc != -1); GLint texCoordLoc = glGetAttribLocation(glProgram, "a_texCoord"); DE_ASSERT(texCoordLoc != -1); GLint samplerLoc = glGetUniformLocation(glProgram, "u_sampler"); DE_ASSERT(samplerLoc != -1); float coords[] = { -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, }; float sampleTexCoords[] = { 10.0, -1.0, -1.0, 10.0, 1.0, -1.0, 10.0, 1.0, 1.0, 10.0, 1.0, 1.0, 10.0, -1.0, 1.0, 10.0, -1.0, -1.0, }; vector<float> texCoords; float sign = 0.0f; int dir = -1; switch (face) { case GL_TEXTURE_CUBE_MAP_POSITIVE_X: sign = 1.0; dir = 0; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: sign = -1.0; dir = 0; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: sign = 1.0; dir = 1; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: sign = -1.0; dir = 1; break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: sign = 1.0; dir = 2; break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: sign = -1.0; dir = 2; break; default: DE_ASSERT(false); } for (int i = 0; i < 6; i++) { texCoords.push_back(sign * sampleTexCoords[i*3 + (dir % 3)]); texCoords.push_back(sampleTexCoords[i*3 + ((dir + 1) % 3)]); texCoords.push_back(sampleTexCoords[i*3 + ((dir + 2) % 3)]); } GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, srcTex)); GLU_CHECK_CALL(glUniform1i(samplerLoc, 0)); GLU_CHECK_CALL(glEnableVertexAttribArray(coordLoc)); GLU_CHECK_CALL(glEnableVertexAttribArray(texCoordLoc)); GLU_CHECK_CALL(glVertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords)); GLU_CHECK_CALL(glVertexAttribPointer(texCoordLoc, 3, GL_FLOAT, GL_FALSE, 0, coords)); GLU_CHECK_CALL(glDrawArrays(GL_TRIANGLES, 0, 6)); GLU_CHECK_CALL(glDisableVertexAttribArray(coordLoc)); GLU_CHECK_CALL(glDisableVertexAttribArray(texCoordLoc)); GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, 0)); GLU_CHECK_CALL(glDeleteTextures(1, &srcTex)); tcu::Surface screen(reference.getWidth(), reference.getHeight()); glReadPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr()); GLU_CHECK_MSG("glReadPixels()"); float threshold = 0.05f; bool match = tcu::fuzzyCompare(m_log, "ComparisonResult", "Image comparison result", reference, screen, threshold, tcu::COMPARE_LOG_RESULT); return match; } void GLES2ImageApi::modify (int operationNdx, EGLImageKHR img, tcu::Texture2D& reference) { switch (operationNdx) { case MODIFY_TEXSUBIMAGE_RGBA8: modifyTexSubImage(img, reference, GL_RGBA, GL_UNSIGNED_BYTE); break; case MODIFY_TEXSUBIMAGE_RGBA5_A1: modifyTexSubImage(img, reference, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1); break; case MODIFY_TEXSUBIMAGE_RGBA4: modifyTexSubImage(img, reference, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4); break; case MODIFY_TEXSUBIMAGE_RGB8: modifyTexSubImage(img, reference, GL_RGB, GL_UNSIGNED_BYTE); break; case MODIFY_TEXSUBIMAGE_RGB565: modifyTexSubImage(img, reference, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); break; case MODIFY_RENDERBUFFER_CLEAR_COLOR: modifyRenderbufferClearColor(img, reference); break; case MODIFY_RENDERBUFFER_CLEAR_DEPTH: modifyRenderbufferClearDepth(img, reference); break; case MODIFY_RENDERBUFFER_CLEAR_STENCIL: modifyRenderbufferClearStencil(img, reference); break; default: DE_ASSERT(false); break; } } void GLES2ImageApi::modifyTexSubImage (EGLImageKHR img, tcu::Texture2D& reference, GLenum format, GLenum type) { m_log << tcu::TestLog::Message << "Modifying EGLImage with glTexSubImage2D" << tcu::TestLog::EndMessage; deUint32 srcTex = 0; glGenTextures(1, &srcTex); TCU_CHECK(srcTex != 0); GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, srcTex)); m_eglExt.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteTextures(1, &srcTex)); throw tcu::NotSupportedError("Creating texture2D from EGLImage type not supported", "glEGLImageTargetTexture2DOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetTexture2DOES() failed"); int xOffset = 8; int yOffset = 16; tcu::Texture2D src(glu::mapGLTransferFormat(format, type), 16, 16); src.allocLevel(0); tcu::fillWithComponentGradients(src.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, srcTex)); GLU_CHECK_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, src.getWidth(), src.getHeight(), format, type, src.getLevel(0).getDataPtr())); for (int x = 0; x < src.getWidth(); x++) { if (x + xOffset >= reference.getWidth()) continue; for (int y = 0; y < src.getHeight(); y++) { if (y + yOffset >= reference.getHeight()) continue; reference.getLevel(0).setPixel(src.getLevel(0).getPixel(x, y), x+xOffset, y+yOffset); } } GLU_CHECK_CALL(glDeleteTextures(1, &srcTex)); GLU_CHECK_CALL(glFinish()); GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, 0)); } void GLES2ImageApi::modifyRenderbufferClearColor (EGLImageKHR img, tcu::Texture2D& reference) { m_log << tcu::TestLog::Message << "Modifying EGLImage with glClear to renderbuffer" << tcu::TestLog::EndMessage; deUint32 framebuffer; glGenFramebuffers(1, &framebuffer); TCU_CHECK(framebuffer != (GLuint)-1); GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer)); deUint32 renderbuffer = 0; glGenRenderbuffers(1, &renderbuffer); TCU_CHECK(renderbuffer != (GLuint)-1); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer)); m_eglExt.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("Creating renderbuffer from EGLImage type not supported", "glEGLImageTargetRenderbufferStorageOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetRenderbufferStorageOES() failed"); float red = 0.3f; float green = 0.5f; float blue = 0.3f; float alpha = 1.0f; GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer)); GLU_CHECK_CALL(glViewport(0, 0, reference.getWidth(), reference.getHeight())); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("EGLImage type as color attachment not supported", "", __FILE__, __LINE__); } GLU_CHECK_CALL(glClearColor(red, green, blue, alpha)); GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT)); for (int x = 0; x < reference.getWidth(); x++) { for (int y = 0; y < reference.getHeight(); y++) { tcu::Vec4 color = tcu::Vec4(red, green, blue, alpha); reference.getLevel(0).setPixel(color, x, y); } } GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glFinish()); } void GLES2ImageApi::modifyRenderbufferClearDepth (EGLImageKHR img, tcu::Texture2D& reference) { m_log << tcu::TestLog::Message << "Modifying EGLImage with glClear to renderbuffer" << tcu::TestLog::EndMessage; deUint32 framebuffer; glGenFramebuffers(1, &framebuffer); TCU_CHECK(framebuffer != (GLuint)-1); GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer)); deUint32 renderbuffer = 0; glGenRenderbuffers(1, &renderbuffer); TCU_CHECK(renderbuffer != 0); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer)); m_eglExt.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("Creating renderbuffer from EGLImage type not supported", "glEGLImageTargetRenderbufferStorageOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetRenderbufferStorageOES() failed"); float depth = 0.7f; GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer)); GLU_CHECK_CALL(glViewport(0, 0, reference.getWidth(), reference.getHeight())); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("EGLImage type as depth attachment not supported", "", __FILE__, __LINE__); } GLU_CHECK_CALL(glClearDepthf(depth)); GLU_CHECK_CALL(glClear(GL_DEPTH_BUFFER_BIT)); for (int x = 0; x < reference.getWidth(); x++) { for (int y = 0; y < reference.getHeight(); y++) { tcu::Vec4 color = tcu::Vec4(depth, depth, depth, depth); reference.getLevel(0).setPixel(color, x, y); } } GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glFinish()); } void GLES2ImageApi::modifyRenderbufferClearStencil (EGLImageKHR img, tcu::Texture2D& reference) { m_log << tcu::TestLog::Message << "Modifying EGLImage with glClear to renderbuffer" << tcu::TestLog::EndMessage; deUint32 framebuffer; glGenFramebuffers(1, &framebuffer); TCU_CHECK(framebuffer != (GLuint)-1); GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer)); deUint32 renderbuffer = 0; glGenRenderbuffers(1, &renderbuffer); TCU_CHECK(renderbuffer != 0); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer)); m_eglExt.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)img); GLenum error = glGetError(); if (error == GL_INVALID_OPERATION) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("Creating renderbuffer from EGLImage type not supported", "glEGLImageTargetRenderbufferStorageOES", __FILE__, __LINE__); } TCU_CHECK(error == GL_NONE); TCU_CHECK_EGL_MSG("glEGLImageTargetRenderbufferStorageOES() failed"); int stencilValue = 78; GLU_CHECK_CALL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer)); GLU_CHECK_CALL(glViewport(0, 0, reference.getWidth(), reference.getHeight())); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); throw tcu::NotSupportedError("EGLImage type as stencil attachment not supported", "", __FILE__, __LINE__); } GLU_CHECK_CALL(glClearStencil(stencilValue)); GLU_CHECK_CALL(glClear(GL_STENCIL_BUFFER_BIT)); for (int x = 0; x < reference.getWidth(); x++) { for (int y = 0; y < reference.getHeight(); y++) { tcu::IVec4 color = tcu::IVec4(stencilValue, stencilValue, stencilValue, stencilValue); reference.getLevel(0).setPixel(color, x, y); } } GLU_CHECK_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0)); GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, 0)); GLU_CHECK_CALL(glDeleteRenderbuffers(1, &renderbuffer)); GLU_CHECK_CALL(glDeleteFramebuffers(1, &framebuffer)); GLU_CHECK_CALL(glFinish()); } void GLES2ImageApi::checkRequiredExtensions (set<string>& extensions, TestSpec::Operation::Type type, int operationNdx) { switch (type) { case TestSpec::Operation::TYPE_CREATE: switch (operationNdx) { case CREATE_TEXTURE2D_RGB8: case CREATE_TEXTURE2D_RGB565: case CREATE_TEXTURE2D_RGBA8: case CREATE_TEXTURE2D_RGBA5_A1: case CREATE_TEXTURE2D_RGBA4: extensions.insert("EGL_KHR_gl_texture_2D_image"); break; case CREATE_CUBE_MAP_POSITIVE_X_RGB8: case CREATE_CUBE_MAP_NEGATIVE_X_RGB8: case CREATE_CUBE_MAP_POSITIVE_Y_RGB8: case CREATE_CUBE_MAP_NEGATIVE_Y_RGB8: case CREATE_CUBE_MAP_POSITIVE_Z_RGB8: case CREATE_CUBE_MAP_NEGATIVE_Z_RGB8: case CREATE_CUBE_MAP_POSITIVE_X_RGBA8: case CREATE_CUBE_MAP_NEGATIVE_X_RGBA8: case CREATE_CUBE_MAP_POSITIVE_Y_RGBA8: case CREATE_CUBE_MAP_NEGATIVE_Y_RGBA8: case CREATE_CUBE_MAP_POSITIVE_Z_RGBA8: case CREATE_CUBE_MAP_NEGATIVE_Z_RGBA8: extensions.insert("EGL_KHR_gl_texture_cubemap_image"); break; case CREATE_RENDER_BUFFER_RGBA4: case CREATE_RENDER_BUFFER_RGB5_A1: case CREATE_RENDER_BUFFER_RGB565: case CREATE_RENDER_BUFFER_DEPTH16: case CREATE_RENDER_BUFFER_STENCIL: extensions.insert("EGL_KHR_gl_renderbuffer_image"); break; default: DE_ASSERT(false); } break; case TestSpec::Operation::TYPE_RENDER: switch (operationNdx) { case RENDER_TEXTURE2D: case RENDER_READ_PIXELS_RENDERBUFFER: case RENDER_DEPTHBUFFER: case RENDER_TRY_ALL: extensions.insert("GL_OES_EGL_image"); break; default: DE_ASSERT(false); break; } break; case TestSpec::Operation::TYPE_MODIFY: switch (operationNdx) { case MODIFY_TEXSUBIMAGE_RGB565: case MODIFY_TEXSUBIMAGE_RGB8: case MODIFY_TEXSUBIMAGE_RGBA8: case MODIFY_TEXSUBIMAGE_RGBA5_A1: case MODIFY_TEXSUBIMAGE_RGBA4: case MODIFY_RENDERBUFFER_CLEAR_COLOR: case MODIFY_RENDERBUFFER_CLEAR_DEPTH: case MODIFY_RENDERBUFFER_CLEAR_STENCIL: extensions.insert("GL_OES_EGL_image"); break; default: DE_ASSERT(false); break; }; break; default: DE_ASSERT(false); break; } } class ImageFormatCase : public TestCase { public: ImageFormatCase (EglTestContext& eglTestCtx, const TestSpec& spec); ~ImageFormatCase (void); void init (void); void deinit (void); IterateResult iterate (void); void checkExtensions (void); private: EGLConfig getConfig (void); const TestSpec m_spec; tcu::TestLog& m_log; vector<ImageApi*> m_apiContexts; tcu::egl::Display* m_display; eglu::NativeWindow* m_window; tcu::egl::Surface* m_surface; EGLConfig m_config; int m_curIter; EGLImageKHR m_img; tcu::Texture2D m_refImg; EglExt m_eglExt; }; EGLConfig ImageFormatCase::getConfig (void) { vector<EGLConfig> configs; eglu::FilterList filter; EGLint attribList[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_ALPHA_SIZE, 1, EGL_DEPTH_SIZE, 8, EGL_NONE }; m_display->chooseConfig(attribList, configs); return configs[0]; } ImageFormatCase::ImageFormatCase (EglTestContext& eglTestCtx, const TestSpec& spec) : TestCase (eglTestCtx, spec.name.c_str(), spec.desc.c_str()) , m_spec (spec) , m_log (eglTestCtx.getTestContext().getLog()) , m_display (DE_NULL) , m_window (DE_NULL) , m_surface (DE_NULL) , m_config (0) , m_curIter (0) , m_img (EGL_NO_IMAGE_KHR) , m_refImg (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1) { } ImageFormatCase::~ImageFormatCase (void) { deinit(); } void ImageFormatCase::checkExtensions (void) { vector<string> extensions; m_display->getExtensions(extensions); set<string> extSet(extensions.begin(), extensions.end()); const char* glExt = (const char*)glGetString(GL_EXTENSIONS); for (const char* c = glExt; true; c++) { if (*c == '\0') { extSet.insert(string(glExt)); break; } if (*c == ' ') { extSet.insert(string(glExt, c)); glExt = (c+1); } } if (extSet.find("EGL_KHR_image_base") == extSet.end() && extSet.find("EGL_KHR_image") == extSet.end()) { m_log << tcu::TestLog::Message << "EGL_KHR_image and EGL_KHR_image_base not supported." << "One should be supported." << tcu::TestLog::EndMessage; throw tcu::NotSupportedError("Extension not supported", "EGL_KHR_image_base", __FILE__, __LINE__); } set<string> requiredExtensions; for (int operationNdx = 0; operationNdx < (int)m_spec.operations.size(); operationNdx++) m_apiContexts[m_spec.operations[m_curIter].apiIndex]->checkRequiredExtensions(requiredExtensions, m_spec.operations[operationNdx].type, m_spec.operations[operationNdx].operationIndex); std::set<string>::iterator extIter = requiredExtensions.begin(); for (; extIter != requiredExtensions.end(); extIter++) { if (extSet.find(*extIter) == extSet.end()) throw tcu::NotSupportedError("Extension not supported", (*extIter).c_str(), __FILE__, __LINE__); } } void ImageFormatCase::init (void) { m_display = &m_eglTestCtx.getDisplay(); m_config = getConfig(); m_window = m_eglTestCtx.createNativeWindow(m_display->getEGLDisplay(), m_config, DE_NULL, 480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())); m_surface = new tcu::egl::WindowSurface(*m_display, eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_display->getEGLDisplay(), m_config, DE_NULL)); for (int contextNdx = 0; contextNdx < (int)m_spec.contexts.size(); contextNdx++) { ImageApi* api = DE_NULL; switch (m_spec.contexts[contextNdx]) { case TestSpec::API_GLES2: { api = new GLES2ImageApi(contextNdx, m_log, *m_display, m_surface, m_config); break; } default: DE_ASSERT(false); break; } m_apiContexts.push_back(api); } checkExtensions(); } void ImageFormatCase::deinit (void) { for (int contexNdx = 0 ; contexNdx < (int)m_apiContexts.size(); contexNdx++) delete m_apiContexts[contexNdx]; m_apiContexts.clear(); delete m_surface; m_surface = DE_NULL; delete m_window; m_window = DE_NULL; } TestCase::IterateResult ImageFormatCase::iterate (void) { bool isOk = true; switch (m_spec.operations[m_curIter].type) { case TestSpec::Operation::TYPE_CREATE: { // Delete old image if exists if (m_img != EGL_NO_IMAGE_KHR) { m_log << tcu::TestLog::Message << "Destroying old EGLImage" << tcu::TestLog::EndMessage; TCU_CHECK_EGL_CALL(m_eglExt.eglDestroyImageKHR(m_display->getEGLDisplay(), m_img)); m_img = EGL_NO_IMAGE_KHR; } m_img = m_apiContexts[m_spec.operations[m_curIter].apiIndex]->create(m_spec.operations[m_curIter].operationIndex, m_refImg); break; } case TestSpec::Operation::TYPE_RENDER: { DE_ASSERT(m_apiContexts[m_spec.operations[m_curIter].apiIndex]); isOk = m_apiContexts[m_spec.operations[m_curIter].apiIndex]->render(m_spec.operations[m_curIter].operationIndex, m_img, m_refImg); break; } case TestSpec::Operation::TYPE_MODIFY: { m_apiContexts[m_spec.operations[m_curIter].apiIndex]->modify(m_spec.operations[m_curIter].operationIndex, m_img, m_refImg); break; } default: DE_ASSERT(false); break; } if (isOk && ++m_curIter < (int)m_spec.operations.size()) { m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return CONTINUE; } else if (!isOk) { if (m_img != EGL_NO_IMAGE_KHR) { m_log << tcu::TestLog::Message << "Destroying EGLImage" << tcu::TestLog::EndMessage; TCU_CHECK_EGL_CALL(m_eglExt.eglDestroyImageKHR(m_display->getEGLDisplay(), m_img)); m_img = EGL_NO_IMAGE_KHR; } m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); return STOP; } else { if (m_img != EGL_NO_IMAGE_KHR) { m_log << tcu::TestLog::Message << "Destroying EGLImage" << tcu::TestLog::EndMessage; TCU_CHECK_EGL_CALL(m_eglExt.eglDestroyImageKHR(m_display->getEGLDisplay(), m_img)); m_img = EGL_NO_IMAGE_KHR; } m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); return STOP; } } SimpleCreationTests::SimpleCreationTests (EglTestContext& eglTestCtx) : TestCaseGroup (eglTestCtx, "create", "EGLImage creation tests") { } #define PUSH_VALUES_TO_VECTOR(type, vector, ...)\ do {\ type array[] = __VA_ARGS__;\ for (int i = 0; i < DE_LENGTH_OF_ARRAY(array); i++)\ {\ vector.push_back(array[i]);\ }\ } while(false); void SimpleCreationTests::init (void) { GLES2ImageApi::Create createOperations[] = { GLES2ImageApi::CREATE_TEXTURE2D_RGB8, GLES2ImageApi::CREATE_TEXTURE2D_RGB565, GLES2ImageApi::CREATE_TEXTURE2D_RGBA8, GLES2ImageApi::CREATE_TEXTURE2D_RGBA5_A1, GLES2ImageApi::CREATE_TEXTURE2D_RGBA4, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_X_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Y_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Z_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_X_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Y_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Z_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_X_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Y_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Z_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_X_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Y_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Z_RGB8, GLES2ImageApi::CREATE_RENDER_BUFFER_RGBA4, GLES2ImageApi::CREATE_RENDER_BUFFER_RGB5_A1, GLES2ImageApi::CREATE_RENDER_BUFFER_RGB565, GLES2ImageApi::CREATE_RENDER_BUFFER_DEPTH16, GLES2ImageApi::CREATE_RENDER_BUFFER_STENCIL }; const char* createOperationsStr[] = { "texture_rgb8", "texture_rgb565", "texture_rgba8", "texture_rgba5_a1", "texture_rgba4", "cubemap_positive_x_rgba", "cubemap_positive_y_rgba", "cubemap_positive_z_rgba", "cubemap_negative_x_rgba", "cubemap_negative_y_rgba", "cubemap_negative_z_rgba", "cubemap_positive_x_rgb", "cubemap_positive_y_rgb", "cubemap_positive_z_rgb", "cubemap_negative_x_rgb", "cubemap_negative_y_rgb", "cubemap_negative_z_rgb", "renderbuffer_rgba4", "renderbuffer_rgb5_a1", "renderbuffer_rgb565", "renderbuffer_depth16", "renderbuffer_stencil" }; GLES2ImageApi::Render renderOperations[] = { GLES2ImageApi::RENDER_TEXTURE2D, GLES2ImageApi::RENDER_READ_PIXELS_RENDERBUFFER, GLES2ImageApi::RENDER_DEPTHBUFFER }; const char* renderOperationsStr[] = { "texture", "read_pixels", "depth_buffer" }; DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(createOperations) == DE_LENGTH_OF_ARRAY(createOperationsStr)); DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(renderOperations) == DE_LENGTH_OF_ARRAY(renderOperationsStr)); for (int createNdx = 0; createNdx < DE_LENGTH_OF_ARRAY(createOperations); createNdx++) { for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderOperations); renderNdx++) { TestSpec spec; spec.name = std::string("gles2_") + createOperationsStr[createNdx] + "_" + renderOperationsStr[renderNdx]; spec.desc = spec.name; PUSH_VALUES_TO_VECTOR(TestSpec::ApiContext, spec.contexts, { TestSpec::API_GLES2 }); PUSH_VALUES_TO_VECTOR(TestSpec::Operation, spec.operations, { { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_CREATE, createOperations[createNdx] }, { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_RENDER, renderOperations[renderNdx] }, }); addChild(new ImageFormatCase(m_eglTestCtx, spec)); } } } MultiContextRenderTests::MultiContextRenderTests (EglTestContext& eglTestCtx) : TestCaseGroup (eglTestCtx, "render_multiple_contexts", "EGLImage render tests on multiple contexts") { } void MultiContextRenderTests::init (void) { GLES2ImageApi::Create createOperations[] = { GLES2ImageApi::CREATE_TEXTURE2D_RGB8, GLES2ImageApi::CREATE_TEXTURE2D_RGB565, GLES2ImageApi::CREATE_TEXTURE2D_RGBA8, GLES2ImageApi::CREATE_TEXTURE2D_RGBA5_A1, GLES2ImageApi::CREATE_TEXTURE2D_RGBA4, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_X_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Y_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Z_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_X_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Y_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Z_RGBA8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_X_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Y_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_POSITIVE_Z_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_X_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Y_RGB8, GLES2ImageApi::CREATE_CUBE_MAP_NEGATIVE_Z_RGB8, GLES2ImageApi::CREATE_RENDER_BUFFER_RGBA4, GLES2ImageApi::CREATE_RENDER_BUFFER_RGB5_A1, GLES2ImageApi::CREATE_RENDER_BUFFER_RGB565, GLES2ImageApi::CREATE_RENDER_BUFFER_DEPTH16, GLES2ImageApi::CREATE_RENDER_BUFFER_STENCIL }; const char* createOperationsStr[] = { "texture_rgb8", "texture_rgb565", "texture_rgba8", "texture_rgba5_a1", "texture_rgba4", "cubemap_positive_x_rgba8", "cubemap_positive_y_rgba8", "cubemap_positive_z_rgba8", "cubemap_negative_x_rgba8", "cubemap_negative_y_rgba8", "cubemap_negative_z_rgba8", "cubemap_positive_x_rgb8", "cubemap_positive_y_rgb8", "cubemap_positive_z_rgb8", "cubemap_negative_x_rgb8", "cubemap_negative_y_rgb8", "cubemap_negative_z_rgb8", "renderbuffer_rgba4", "renderbuffer_rgb5_a1", "renderbuffer_rgb565", "renderbuffer_depth16", "renderbuffer_stencil" }; GLES2ImageApi::Render renderOperations[] = { GLES2ImageApi::RENDER_TEXTURE2D, GLES2ImageApi::RENDER_READ_PIXELS_RENDERBUFFER, GLES2ImageApi::RENDER_DEPTHBUFFER }; const char* renderOperationsStr[] = { "texture", "read_pixels", "depth_buffer" }; DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(createOperations) == DE_LENGTH_OF_ARRAY(createOperationsStr)); DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(renderOperations) == DE_LENGTH_OF_ARRAY(renderOperationsStr)); for (int createNdx = 0; createNdx < DE_LENGTH_OF_ARRAY(createOperations); createNdx++) { for (int renderNdx = 0; renderNdx < DE_LENGTH_OF_ARRAY(renderOperations); renderNdx++) { TestSpec spec; spec.name = std::string("gles2_") + createOperationsStr[createNdx] + "_" + renderOperationsStr[renderNdx]; spec.desc = spec.name; PUSH_VALUES_TO_VECTOR(TestSpec::ApiContext, spec.contexts, { TestSpec::API_GLES2, TestSpec::API_GLES2 }); PUSH_VALUES_TO_VECTOR(TestSpec::Operation, spec.operations, { { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_CREATE, createOperations[createNdx] }, { TestSpec::API_GLES2, 1, TestSpec::Operation::TYPE_RENDER, renderOperations[renderNdx] }, { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_RENDER, renderOperations[renderNdx] }, { TestSpec::API_GLES2, 1, TestSpec::Operation::TYPE_CREATE, createOperations[createNdx] }, { TestSpec::API_GLES2, 1, TestSpec::Operation::TYPE_RENDER, renderOperations[renderNdx] }, { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_RENDER, renderOperations[renderNdx] } }); addChild(new ImageFormatCase(m_eglTestCtx, spec)); } } } ModifyTests::ModifyTests (EglTestContext& eglTestCtx) : TestCaseGroup (eglTestCtx, "modify", "EGLImage modifying tests") { } void ModifyTests::init (void) { GLES2ImageApi::Create createOperations[] = { GLES2ImageApi::CREATE_TEXTURE2D_RGB8, GLES2ImageApi::CREATE_TEXTURE2D_RGB565, GLES2ImageApi::CREATE_TEXTURE2D_RGBA8, GLES2ImageApi::CREATE_TEXTURE2D_RGBA5_A1, GLES2ImageApi::CREATE_TEXTURE2D_RGBA4, GLES2ImageApi::CREATE_RENDER_BUFFER_RGBA4, GLES2ImageApi::CREATE_RENDER_BUFFER_RGB5_A1, GLES2ImageApi::CREATE_RENDER_BUFFER_RGB565, GLES2ImageApi::CREATE_RENDER_BUFFER_DEPTH16, GLES2ImageApi::CREATE_RENDER_BUFFER_STENCIL }; const char* createOperationsStr[] = { "tex_rgb8", "tex_rgb565", "tex_rgba8", "tex_rgba5_a1", "tex_rgba4", "renderbuffer_rgba4", "renderbuffer_rgb5_a1", "renderbuffer_rgb565", "renderbuffer_depth16", "renderbuffer_stencil" }; GLES2ImageApi::Modify modifyOperations[] = { GLES2ImageApi::MODIFY_TEXSUBIMAGE_RGB8, GLES2ImageApi::MODIFY_TEXSUBIMAGE_RGB565, GLES2ImageApi::MODIFY_TEXSUBIMAGE_RGBA8, GLES2ImageApi::MODIFY_TEXSUBIMAGE_RGBA5_A1, GLES2ImageApi::MODIFY_TEXSUBIMAGE_RGBA4, GLES2ImageApi::MODIFY_RENDERBUFFER_CLEAR_COLOR, GLES2ImageApi::MODIFY_RENDERBUFFER_CLEAR_DEPTH, GLES2ImageApi::MODIFY_RENDERBUFFER_CLEAR_STENCIL, }; const char* modifyOperationsStr[] = { "tex_subimage_rgb8", "tex_subimage_rgb565", "tex_subimage_rgba8", "tex_subimage_rgba5_a1", "tex_subimage_rgba4", "renderbuffer_clear_color", "renderbuffer_clear_depth", "renderbuffer_clear_stencil", }; DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(modifyOperations) == DE_LENGTH_OF_ARRAY(modifyOperationsStr)); DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(createOperations) == DE_LENGTH_OF_ARRAY(createOperationsStr)); for (int createNdx = 0; createNdx < DE_LENGTH_OF_ARRAY(createOperations); createNdx++) { for (int modifyNdx = 0; modifyNdx < DE_LENGTH_OF_ARRAY(modifyOperations); modifyNdx++) { TestSpec spec; spec.name = "gles2_tex_sub_image"; spec.desc = spec.name; PUSH_VALUES_TO_VECTOR(TestSpec::ApiContext, spec.contexts, { TestSpec::API_GLES2 }); PUSH_VALUES_TO_VECTOR(TestSpec::Operation, spec.operations, { { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_CREATE, createOperations[createNdx] }, { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_RENDER, GLES2ImageApi::RENDER_TRY_ALL }, { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_MODIFY, modifyOperations[modifyNdx] }, { TestSpec::API_GLES2, 0, TestSpec::Operation::TYPE_RENDER, GLES2ImageApi::RENDER_TRY_ALL } }); spec.name = std::string(createOperationsStr[createNdx]) + "_" + modifyOperationsStr[modifyNdx]; addChild(new ImageFormatCase(m_eglTestCtx, spec)); } } } } // Image } // egl } // deqp