| /*------------------------------------------------------------------------- |
| * 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 "deStringUtil.hpp" |
| #include "deSTLUtil.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 "egluUnique.hpp" |
| #include "egluUtil.hpp" |
| |
| #include "eglwLibrary.hpp" |
| #include "eglwEnums.hpp" |
| |
| #include "gluCallLogWrapper.hpp" |
| #include "gluShaderProgram.hpp" |
| #include "gluStrUtil.hpp" |
| #include "gluTexture.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluObjectWrapper.hpp" |
| #include "gluTextureUtil.hpp" |
| |
| #include "glwEnums.hpp" |
| #include "glwFunctions.hpp" |
| |
| #include "teglImageUtil.hpp" |
| #include "teglAndroidUtil.hpp" |
| |
| #include <vector> |
| #include <string> |
| #include <set> |
| |
| using std::vector; |
| using std::set; |
| using std::string; |
| |
| using de::MovePtr; |
| using de::UniquePtr; |
| |
| using glu::Framebuffer; |
| using glu::Renderbuffer; |
| using glu::Texture; |
| |
| using eglu::UniqueImage; |
| |
| using tcu::ConstPixelBufferAccess; |
| |
| using namespace glw; |
| using namespace eglw; |
| |
| namespace deqp |
| { |
| namespace egl |
| { |
| |
| namespace |
| { |
| |
| glu::ProgramSources programSources (const string& vertexSource, const string& fragmentSource) |
| { |
| glu::ProgramSources sources; |
| |
| sources << glu::VertexSource(vertexSource) << glu::FragmentSource(fragmentSource); |
| |
| return sources; |
| } |
| |
| class Program : public glu::ShaderProgram |
| { |
| public: |
| Program (const glw::Functions& gl, const char* vertexSource, const char* fragmentSource) |
| : glu::ShaderProgram(gl, programSources(vertexSource, fragmentSource)) {} |
| }; |
| |
| } // anonymous |
| |
| namespace Image |
| { |
| |
| class ImageApi; |
| |
| class IllegalRendererException : public std::exception |
| { |
| }; |
| |
| class Action |
| { |
| public: |
| virtual ~Action (void) {} |
| virtual bool invoke (ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& refImg) const = 0; |
| virtual string getRequiredExtension (void) const = 0; |
| }; |
| |
| struct TestSpec |
| { |
| std::string name; |
| std::string desc; |
| |
| enum ApiContext |
| { |
| API_GLES2 = 0, |
| API_GLES3, |
| //API_VG |
| //API_GLES1 |
| |
| API_LAST |
| }; |
| |
| struct Operation |
| { |
| Operation (int apiIndex_, const Action& action_) : apiIndex(apiIndex_), action(&action_) {} |
| int apiIndex; |
| const Action* action; |
| }; |
| |
| vector<ApiContext> contexts; |
| vector<Operation> operations; |
| |
| }; |
| |
| class ImageApi |
| { |
| public: |
| ImageApi (const Library& egl, int contextId, EGLDisplay display, EGLSurface surface); |
| virtual ~ImageApi (void) {} |
| |
| protected: |
| const Library& m_egl; |
| int m_contextId; |
| EGLDisplay m_display; |
| EGLSurface m_surface; |
| }; |
| |
| ImageApi::ImageApi (const Library& egl, int contextId, EGLDisplay display, EGLSurface surface) |
| : m_egl (egl) |
| , m_contextId (contextId) |
| , m_display (display) |
| , m_surface (surface) |
| { |
| } |
| |
| class GLESImageApi : public ImageApi, private glu::CallLogWrapper |
| { |
| public: |
| class GLESAction : public Action |
| { |
| public: |
| bool invoke (ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; |
| virtual bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const = 0; |
| }; |
| |
| class Create : public GLESAction |
| { |
| public: |
| Create (MovePtr<ImageSource> imgSource, deUint32 numLayers = 1u) : m_imgSource(imgSource), m_numLayers(numLayers) {} |
| string getRequiredExtension (void) const { return m_imgSource->getRequiredExtension(); } |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; |
| deUint32 getNumLayers (void) const { return m_numLayers; } |
| glw::GLenum getEffectiveFormat (void) const { return m_imgSource->getEffectiveFormat(); } |
| bool isYUVFormatImage (void) const { return m_imgSource->isYUVFormatImage(); } |
| private: |
| UniquePtr<ImageSource> m_imgSource; |
| deUint32 m_numLayers; |
| }; |
| |
| class Render : public GLESAction |
| { |
| public: |
| virtual string getRequiredExtension (void) const { return "GL_OES_EGL_image"; } |
| }; |
| |
| class RenderTexture2D : public Render { public: bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; }; |
| class RenderTextureCubemap : public Render { public: bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; }; |
| class RenderReadPixelsRenderbuffer : public Render { public: bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; }; |
| class RenderDepthbuffer : public Render { public: bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; }; |
| class RenderStencilbuffer : public Render { public: bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; }; |
| class RenderTryAll : public Render { public: bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; }; |
| |
| class RenderTexture2DArray : public Render |
| { |
| public: |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; |
| string getRequiredExtension (void) const override { return "GL_EXT_EGL_image_array"; } |
| }; |
| |
| class RenderExternalTexture : public Render |
| { |
| public: |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; |
| string getRequiredExtension (void) const override { return "GL_OES_EGL_image_external"; } |
| }; |
| |
| class RenderExternalTextureSamplerArray : public Render |
| { |
| public: |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; |
| string getRequiredExtension (void) const override { return "GL_OES_EGL_image_external"; } |
| }; |
| class RenderYUVTexture : public Render |
| { |
| public: |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; |
| string getRequiredExtension (void) const override { return "GL_EXT_YUV_target"; } |
| }; |
| class RenderSampleTexture2DArray : public RenderTexture2DArray |
| { |
| public: |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const override; |
| string getRequiredExtension (void) const override { return "GL_EXT_EGL_image_array"; } |
| }; |
| class Modify : public GLESAction |
| { |
| public: |
| string getRequiredExtension (void) const { return "GL_OES_EGL_image"; } |
| }; |
| |
| class ModifyTexSubImage : public Modify |
| { |
| public: |
| ModifyTexSubImage (GLenum format, GLenum type) : m_format(format), m_type(type) {} |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; |
| GLenum getFormat (void) const { return m_format; } |
| GLenum getType (void) const { return m_type; } |
| |
| private: |
| GLenum m_format; |
| GLenum m_type; |
| }; |
| |
| class ModifyRenderbuffer : public Modify |
| { |
| public: |
| bool invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; |
| |
| protected: |
| virtual void initializeRbo (GLESImageApi& api, GLuint rbo, tcu::Texture2D& ref) const = 0; |
| }; |
| |
| class ModifyRenderbufferClearColor : public ModifyRenderbuffer |
| { |
| public: |
| ModifyRenderbufferClearColor (tcu::Vec4 color) : m_color(color) {} |
| |
| protected: |
| void initializeRbo (GLESImageApi& api, GLuint rbo, tcu::Texture2D& ref) const; |
| |
| tcu::Vec4 m_color; |
| }; |
| |
| class ModifyRenderbufferClearDepth : public ModifyRenderbuffer |
| { |
| public: |
| ModifyRenderbufferClearDepth (GLfloat depth) : m_depth(depth) {} |
| |
| protected: |
| void initializeRbo (GLESImageApi& api, GLuint rbo, tcu::Texture2D& ref) const; |
| |
| GLfloat m_depth; |
| }; |
| |
| class ModifyRenderbufferClearStencil : public ModifyRenderbuffer |
| { |
| public: |
| ModifyRenderbufferClearStencil (GLint stencil) : m_stencil(stencil) {} |
| |
| protected: |
| void initializeRbo (GLESImageApi& api, GLuint rbo, tcu::Texture2D& ref) const; |
| |
| GLint m_stencil; |
| }; |
| |
| GLESImageApi (const Library& egl, const glw::Functions& gl, int contextId, tcu::TestLog& log, EGLDisplay display, EGLSurface surface, EGLConfig config, EGLint apiVersion); |
| ~GLESImageApi (void); |
| |
| private: |
| EGLContext m_context; |
| const glw::Functions& m_gl; |
| |
| MovePtr<UniqueImage> createImage (const ImageSource& source, const ClientBuffer& buffer) const; |
| }; |
| |
| GLESImageApi::GLESImageApi (const Library& egl, const glw::Functions& gl, int contextId, tcu::TestLog& log, EGLDisplay display, EGLSurface surface, EGLConfig config, EGLint apiVersion) |
| : ImageApi (egl, contextId, display, surface) |
| , glu::CallLogWrapper (gl, log) |
| , m_context (DE_NULL) |
| , m_gl (gl) |
| { |
| const EGLint attriblist[] = |
| { |
| EGL_CONTEXT_CLIENT_VERSION, apiVersion, |
| EGL_NONE |
| }; |
| |
| EGLint configId = -1; |
| EGLU_CHECK_CALL(m_egl, getConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId)); |
| getLog() << tcu::TestLog::Message << "Creating gles" << apiVersion << " context with config id: " << configId << " context: " << m_contextId << tcu::TestLog::EndMessage; |
| egl.bindAPI(EGL_OPENGL_ES_API); |
| m_context = m_egl.createContext(m_display, config, EGL_NO_CONTEXT, attriblist); |
| EGLU_CHECK_MSG(m_egl, "Failed to create GLES context"); |
| |
| egl.makeCurrent(display, m_surface, m_surface, m_context); |
| EGLU_CHECK_MSG(m_egl, "Failed to make context current"); |
| } |
| |
| GLESImageApi::~GLESImageApi (void) |
| { |
| m_egl.makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); |
| m_egl.destroyContext(m_display, m_context); |
| } |
| |
| bool GLESImageApi::GLESAction::invoke (ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const |
| { |
| GLESImageApi& glesApi = dynamic_cast<GLESImageApi&>(api); |
| |
| glesApi.m_egl.makeCurrent(glesApi.m_display, glesApi.m_surface, glesApi.m_surface, glesApi.m_context); |
| return invokeGLES(glesApi, image, ref); |
| } |
| |
| bool GLESImageApi::Create::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const |
| { |
| de::UniquePtr<ClientBuffer> buffer (m_imgSource->createBuffer(api.m_egl, api.m_gl, &ref)); |
| |
| GLU_CHECK_GLW_CALL(api.m_gl, finish()); |
| |
| image = api.createImage(*m_imgSource, *buffer); |
| return true; |
| } |
| |
| MovePtr<UniqueImage> GLESImageApi::createImage (const ImageSource& source, const ClientBuffer& buffer) const |
| { |
| const EGLImageKHR image = source.createImage(m_egl, m_display, m_context, buffer.get()); |
| return MovePtr<UniqueImage>(new UniqueImage(m_egl, m_display, image)); |
| } |
| |
| static void imageTargetTexture2D (const Library& egl, const glw::Functions& gl, GLeglImageOES img) |
| { |
| gl.eglImageTargetTexture2DOES(GL_TEXTURE_2D, img); |
| { |
| const GLenum error = gl.getError(); |
| |
| if (error == GL_INVALID_OPERATION) |
| TCU_THROW(NotSupportedError, "Creating texture2D from EGLImage type not supported"); |
| |
| GLU_EXPECT_NO_ERROR(error, "glEGLImageTargetTexture2DOES()"); |
| EGLU_CHECK_MSG(egl, "glEGLImageTargetTexture2DOES()"); |
| } |
| } |
| |
| static void imageTargetExternalTexture (const Library& egl, const glw::Functions& gl, GLeglImageOES img) |
| { |
| gl.eglImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, img); |
| { |
| const GLenum error = gl.getError(); |
| |
| if (error == GL_INVALID_OPERATION) |
| TCU_THROW(NotSupportedError, "Creating external texture from EGLImage type not supported"); |
| |
| GLU_EXPECT_NO_ERROR(error, "glEGLImageTargetTexture2DOES()"); |
| EGLU_CHECK_MSG(egl, "glEGLImageTargetTexture2DOES()"); |
| } |
| } |
| |
| static void imageTargetTexture2DArray (const Library& egl, const glw::Functions& gl, GLeglImageOES img) |
| { |
| gl.eglImageTargetTexture2DOES(GL_TEXTURE_2D_ARRAY, img); |
| { |
| const GLenum error = gl.getError(); |
| |
| if (error == GL_INVALID_OPERATION) |
| TCU_THROW(NotSupportedError, "Creating texture2D array from EGLImage type not supported"); |
| |
| GLU_EXPECT_NO_ERROR(error, "glEGLImageTargetTexture2DOES()"); |
| EGLU_CHECK_MSG(egl, "glEGLImageTargetTexture2DOES()"); |
| } |
| } |
| |
| static void imageTargetRenderbuffer (const Library& egl, const glw::Functions& gl, GLeglImageOES img) |
| { |
| gl.eglImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, img); |
| { |
| const GLenum error = gl.getError(); |
| |
| if (error == GL_INVALID_OPERATION) |
| TCU_THROW(NotSupportedError, "Creating renderbuffer from EGLImage type not supported"); |
| |
| GLU_EXPECT_NO_ERROR(error, "glEGLImageTargetRenderbufferStorageOES()"); |
| EGLU_CHECK_MSG(egl, "glEGLImageTargetRenderbufferStorageOES()"); |
| } |
| } |
| |
| static void framebufferRenderbuffer (const glw::Functions& gl, GLenum attachment, GLuint rbo) |
| { |
| GLU_CHECK_GLW_CALL(gl, framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbo)); |
| TCU_CHECK_AND_THROW(NotSupportedError, |
| gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, |
| ("EGLImage as " + string(glu::getFramebufferAttachmentName(attachment)) + " not supported").c_str()); |
| } |
| |
| static set<string> getSupportedExtensions (tcu::TestLog& log, const Library& egl, const EGLDisplay dpy, const glw::Functions gl) |
| { |
| set<string> exts; |
| const vector<string> glExts = de::splitString((const char*) gl.getString(GL_EXTENSIONS)); |
| const vector<string> eglExts = eglu::getDisplayExtensions(egl, dpy); |
| |
| exts.insert(glExts.begin(), glExts.end()); |
| exts.insert(eglExts.begin(), eglExts.end()); |
| |
| if (eglu::getVersion(egl, dpy) >= eglu::Version(1, 5)) |
| { |
| // EGL 1.5 has built-in support for EGLImage and GL sources |
| exts.insert("EGL_KHR_image_base"); |
| exts.insert("EGL_KHR_gl_texture_2D_image"); |
| exts.insert("EGL_KHR_gl_texture_cubemap_image"); |
| exts.insert("EGL_KHR_gl_renderbuffer_image"); |
| } |
| |
| if (!de::contains(exts, "EGL_KHR_image_base") && !de::contains(exts, "EGL_KHR_image")) |
| { |
| log << tcu::TestLog::Message |
| << "EGL version is under 1.5 and neither EGL_KHR_image nor EGL_KHR_image_base is supported." |
| << "One should be supported." |
| << tcu::TestLog::EndMessage; |
| TCU_THROW(NotSupportedError, "Extension not supported: EGL_KHR_image_base"); |
| } |
| |
| return exts; |
| } |
| |
| static const float squareTriangleCoords[] = |
| { |
| -1.0, -1.0, |
| 1.0, -1.0, |
| 1.0, 1.0, |
| |
| 1.0, 1.0, |
| -1.0, 1.0, |
| -1.0, -1.0 |
| }; |
| |
| bool GLESImageApi::RenderTexture2D::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Texture srcTex (gl); |
| |
| // Branch only taken in TryAll case |
| if (reference.getFormat().order == tcu::TextureFormat::DS || reference.getFormat().order == tcu::TextureFormat::D) |
| throw IllegalRendererException(); // Skip, GLES does not support sampling depth textures |
| if (reference.getFormat().order == tcu::TextureFormat::S) |
| throw IllegalRendererException(); // Skip, GLES does not support sampling stencil textures |
| |
| gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| gl.viewport(0, 0, reference.getWidth(), reference.getHeight()); |
| gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
| gl.disable(GL_DEPTH_TEST); |
| |
| log << tcu::TestLog::Message << "Rendering EGLImage as GL_TEXTURE_2D in context: " << api.m_contextId << tcu::TestLog::EndMessage; |
| TCU_CHECK(**img != EGL_NO_IMAGE_KHR); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, *srcTex)); |
| imageTargetTexture2D(api.m_egl, gl, **img); |
| |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); |
| |
| const char* const 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* const 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(gl, vertexShader, fragmentShader); |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); |
| |
| GLuint samplerLoc = gl.getUniformLocation(glProgram, "u_sampler"); |
| TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform u_sampler"); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, *srcTex)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc, 0)); |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, 0)); |
| |
| tcu::Surface refSurface (reference.getWidth(), reference.getHeight()); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr())); |
| |
| tcu::copy(refSurface.getAccess(), reference.getLevel(0)); |
| |
| float threshold = 0.05f; |
| bool match = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface, screen, threshold, tcu::COMPARE_LOG_RESULT); |
| |
| return match; |
| } |
| |
| // Renders using a single layer from a texture array. |
| bool GLESImageApi::RenderTexture2DArray::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Texture srcTex (gl); |
| |
| gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| gl.viewport(0, 0, reference.getWidth(), reference.getHeight()); |
| gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
| gl.disable(GL_DEPTH_TEST); |
| |
| log << tcu::TestLog::Message << "Rendering EGLImage as GL_TEXTURE_2D_ARRAY in context: " << api.m_contextId << tcu::TestLog::EndMessage; |
| TCU_CHECK(**img != EGL_NO_IMAGE_KHR); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D_ARRAY, *srcTex)); |
| imageTargetTexture2DArray(api.m_egl, gl, **img); |
| |
| glu::TransferFormat transferFormat = glu::getTransferFormat(reference.getFormat()); |
| // Initializes layer 1. |
| GLU_CHECK_GLW_CALL(gl, texSubImage3D(GL_TEXTURE_2D_ARRAY, |
| 0, // Mipmap level |
| 0, // X offset |
| 0, // Y offset |
| 1, // Z offset (layer) |
| reference.getWidth(), // Width |
| reference.getHeight(), // Height |
| 1u, // Depth |
| transferFormat.format, // Format |
| transferFormat.dataType, // Type |
| reference.getLevel(0).getDataPtr())); // Pixel data |
| |
| |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); |
| |
| const char* const vertexShader = |
| "#version 320 es\n" |
| "precision highp int;\n" |
| "precision highp float;\n" |
| "layout(location = 0) in vec2 pos_in;\n" |
| "layout(location = 0) out vec2 texcoord_out;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(pos_in, -0.1, 1.0);\n" |
| " texcoord_out = vec2((pos_in.x + 1.0) * 0.5, (pos_in.y + 1.0) * 0.5);\n" |
| "}\n"; |
| |
| const char* const fragmentShader = |
| "#version 320 es\n" |
| "precision highp int;\n" |
| "precision highp float;\n" |
| "layout(location = 0) in vec2 texcoords_in;\n" |
| "layout(location = 0) out vec4 color_out;\n" |
| "uniform layout(binding=0) highp sampler2DArray tex_sampler;\n" |
| "void main()\n" |
| "{\n" |
| // Samples layer 1. |
| " color_out = texture(tex_sampler, vec3(texcoords_in, 1));\n" |
| "}\n"; |
| |
| Program program(gl, vertexShader, fragmentShader); |
| |
| if (!program.isOk()) |
| { |
| log << tcu::TestLog::Message << "Shader build failed.\n" |
| << "Vertex: " << program.getShaderInfo(glu::SHADERTYPE_VERTEX).infoLog << "\n" |
| << vertexShader << "\n" |
| << "Fragment: " << program.getShaderInfo(glu::SHADERTYPE_FRAGMENT).infoLog << "\n" |
| << fragmentShader << "\n" |
| << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage; |
| } |
| |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram, "pos_in"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute pos_in"); |
| |
| GLuint samplerLoc = gl.getUniformLocation(glProgram, "tex_sampler"); |
| TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform tex_sampler"); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D_ARRAY, *srcTex)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc, 0)); |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| |
| tcu::Surface refSurface (reference.getWidth(), reference.getHeight()); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr())); |
| |
| tcu::copy(refSurface.getAccess(), reference.getLevel(0)); |
| |
| float threshold = 0.05f; |
| bool match = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface, screen, threshold, tcu::COMPARE_LOG_RESULT); |
| |
| return match; |
| } |
| |
| //Texture2D array can be both rendered and sampled as a texture. |
| bool GLESImageApi::RenderSampleTexture2DArray::invokeGLES(GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Texture srcTex (gl); |
| Texture srcTexArray (gl); |
| |
| gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| gl.viewport(0, 0, reference.getWidth(), reference.getHeight()); |
| gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
| gl.disable(GL_DEPTH_TEST); |
| |
| log << tcu::TestLog::Message << "Rendering and sampling EGLImage as GL_TEXTURE_2D_ARRAY in context: " << api.m_contextId << tcu::TestLog::EndMessage; |
| TCU_CHECK(**img != EGL_NO_IMAGE_KHR); |
| |
| glu::TransferFormat transferFormat = glu::getTransferFormat(reference.getFormat()); |
| deUint32 internalForat = glu::getInternalFormat(reference.getFormat()); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, *srcTex)); |
| GLU_CHECK_GLW_CALL(gl, texImage2D(GL_TEXTURE_2D, |
| 0, // Level |
| internalForat, // Internal format |
| reference.getWidth(), // Width |
| reference.getHeight(), // Height |
| 0, // Border |
| transferFormat.format, // Format |
| transferFormat.dataType, // Type |
| reference.getLevel(0).getDataPtr())); // Pixel data |
| |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D_ARRAY, *srcTexArray)); |
| imageTargetTexture2DArray(api.m_egl, gl, **img); |
| |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); |
| |
| /* Create FBO and attach source texture layer 0 */ |
| glu::Framebuffer fbo(gl); |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *fbo)); |
| GLU_CHECK_GLW_CALL(gl, framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, *srcTexArray, 0, 0)); |
| |
| const char* const vertexShader0 = |
| "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* const fragmentShader0 = |
| "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 program0(gl, vertexShader0, fragmentShader0); |
| if (!program0.isOk()) |
| { |
| log << tcu::TestLog::Message << "Shader build failed.\n" |
| << "Vertex: " << program0.getShaderInfo(glu::SHADERTYPE_VERTEX).infoLog << "\n" |
| << vertexShader0 << "\n" |
| << "Fragment: " << program0.getShaderInfo(glu::SHADERTYPE_FRAGMENT).infoLog << "\n" |
| << fragmentShader0 << "\n" |
| << "Program: " << program0.getProgramInfo().infoLog << tcu::TestLog::EndMessage; |
| } |
| |
| TCU_CHECK(program0.isOk()); |
| |
| GLuint glProgram0 = program0.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram0)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram0, "a_coord"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); |
| GLuint samplerLoc = gl.getUniformLocation(glProgram0, "u_sampler"); |
| TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform u_sampler"); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc, 0)); |
| |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| |
| tcu::Surface refSurface0 (reference.getWidth(), reference.getHeight()); |
| tcu::Surface screen0 (reference.getWidth(), reference.getHeight()); |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen0.getWidth(), screen0.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen0.getAccess().getDataPtr())); |
| |
| tcu::copy(refSurface0.getAccess(), reference.getLevel(0)); |
| |
| float threshold = 0.01f; |
| bool match = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface0, screen0, threshold, tcu::COMPARE_LOG_RESULT); |
| |
| if (match == false) |
| return match; |
| |
| /* Bind texture to FBO. */ |
| GLU_CHECK_GLW_CALL(gl, framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *srcTex, 0)); |
| |
| const char* const vertexShader = |
| "#version 320 es\n" |
| "precision highp int;\n" |
| "precision highp float;\n" |
| "layout(location = 0) in vec2 pos_in;\n" |
| "layout(location = 0) out vec2 texcoord_out;\n" |
| "void main()\n" |
| "{\n" |
| " gl_Position = vec4(pos_in, -0.1, 1.0);\n" |
| " texcoord_out = vec2((pos_in.x + 1.0) * 0.5, (pos_in.y + 1.0) * 0.5);\n" |
| "}\n"; |
| |
| const char* const fragmentShader = |
| "#version 320 es\n" |
| "precision highp int;\n" |
| "precision highp float;\n" |
| "layout(location = 0) in vec2 texcoords_in;\n" |
| "layout(location = 0) out vec4 color_out;\n" |
| "uniform layout(binding=0) highp sampler2DArray tex_sampler;\n" |
| "void main()\n" |
| "{\n" |
| // Samples layer 0. |
| " color_out = texture(tex_sampler, vec3(texcoords_in, 0));\n" |
| "}\n"; |
| |
| Program program(gl, vertexShader, fragmentShader); |
| |
| if (!program.isOk()) |
| { |
| log << tcu::TestLog::Message << "Shader build failed.\n" |
| << "Vertex: " << program.getShaderInfo(glu::SHADERTYPE_VERTEX).infoLog << "\n" |
| << vertexShader << "\n" |
| << "Fragment: " << program.getShaderInfo(glu::SHADERTYPE_FRAGMENT).infoLog << "\n" |
| << fragmentShader << "\n" |
| << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage; |
| } |
| |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| coordLoc = gl.getAttribLocation(glProgram, "pos_in"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute pos_in"); |
| |
| samplerLoc = gl.getUniformLocation(glProgram, "tex_sampler"); |
| TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform tex_sampler"); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D_ARRAY, *srcTexArray)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc, 0)); |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| |
| tcu::Surface refSurface (reference.getWidth(), reference.getHeight()); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr())); |
| |
| tcu::copy(refSurface.getAccess(), reference.getLevel(0)); |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0)); |
| |
| threshold = 0.01f; |
| match = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface, screen, threshold, tcu::COMPARE_LOG_RESULT); |
| return match; |
| } |
| |
| bool GLESImageApi::RenderExternalTexture::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Texture srcTex (gl); |
| |
| // Branch only taken in TryAll case |
| if (reference.getFormat().order == tcu::TextureFormat::DS || reference.getFormat().order == tcu::TextureFormat::D) |
| throw IllegalRendererException(); // Skip, GLES2 does not support sampling depth textures |
| if (reference.getFormat().order == tcu::TextureFormat::S) |
| throw IllegalRendererException(); // Skip, GLES2 does not support sampling stencil textures |
| |
| gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| gl.viewport(0, 0, reference.getWidth(), reference.getHeight()); |
| gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
| gl.disable(GL_DEPTH_TEST); |
| |
| log << tcu::TestLog::Message << "Rendering EGLImage as GL_TEXTURE_EXTERNAL_OES in context: " << api.m_contextId << tcu::TestLog::EndMessage; |
| TCU_CHECK(**img != EGL_NO_IMAGE_KHR); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, *srcTex)); |
| imageTargetExternalTexture(api.m_egl, gl, **img); |
| |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); |
| |
| const char* const 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* const fragmentShader = |
| "#extension GL_OES_EGL_image_external : require\n" |
| "varying mediump vec2 v_texCoord;\n" |
| "uniform samplerExternalOES u_sampler;\n" |
| "void main(void) {\n" |
| "\tmediump vec4 texColor = texture2D(u_sampler, v_texCoord);\n" |
| "\tgl_FragColor = vec4(texColor);\n" |
| "}"; |
| |
| Program program(gl, vertexShader, fragmentShader); |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); |
| |
| GLuint samplerLoc = gl.getUniformLocation(glProgram, "u_sampler"); |
| TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform u_sampler"); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, *srcTex)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc, 0)); |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, 0)); |
| |
| tcu::Surface refSurface (reference.getWidth(), reference.getHeight()); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr())); |
| |
| tcu::copy(refSurface.getAccess(), reference.getLevel(0)); |
| |
| float threshold = 0.05f; |
| bool match = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface, screen, threshold, tcu::COMPARE_LOG_RESULT); |
| |
| return match; |
| } |
| |
| bool GLESImageApi::RenderYUVTexture::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Texture srcTex (gl); |
| |
| DE_ASSERT(reference.isYUVTextureUsed()); |
| |
| gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| gl.viewport(0, 0, reference.getWidth(), reference.getHeight()); |
| gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
| gl.disable(GL_DEPTH_TEST); |
| |
| log << tcu::TestLog::Message << "Rendering EGLImage as GL_TEXTURE_EXTERNAL_OES in context: " << api.m_contextId << tcu::TestLog::EndMessage; |
| TCU_CHECK(**img != EGL_NO_IMAGE_KHR); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, *srcTex)); |
| imageTargetExternalTexture(api.m_egl, gl, **img); |
| { |
| /* init YUV texture with glClear, clear color value in YUV color space */ |
| glu::Framebuffer fbo(gl); |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *fbo)); |
| GLU_CHECK_GLW_CALL(gl, framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES,*srcTex, 0)); |
| const tcu::Vec4 colorValues[] = |
| { |
| tcu::Vec4(0.9f, 0.5f, 0.65f, 1.0f), |
| tcu::Vec4(0.5f, 0.7f, 0.65f, 1.0f), |
| tcu::Vec4(0.2f, 0.5f, 0.65f, 1.0f), |
| tcu::Vec4(0.3f, 0.1f, 0.5f, 1.0f), |
| tcu::Vec4(0.8f, 0.2f, 0.3f, 1.0f), |
| tcu::Vec4(0.9f, 0.4f, 0.8f, 1.0f), |
| }; |
| tcu::clear(reference.getLevel(0), tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); |
| GLU_CHECK_GLW_CALL(gl, enable(GL_SCISSOR_TEST)); |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(colorValues); ++ndx) |
| { |
| const tcu::IVec2 size = tcu::IVec2((int)((float)(DE_LENGTH_OF_ARRAY(colorValues) - ndx) * ((float)reference.getWidth() / float(DE_LENGTH_OF_ARRAY(colorValues)))), |
| (int)((float)(DE_LENGTH_OF_ARRAY(colorValues) - ndx) * ((float)reference.getHeight() / float(DE_LENGTH_OF_ARRAY(colorValues))))); |
| |
| if (size.x() == 0 || size.y() == 0) |
| break; |
| GLU_CHECK_GLW_CALL(gl, scissor(0, 0, size.x(), size.y())); |
| |
| GLU_CHECK_GLW_CALL(gl, clearColor(colorValues[ndx].x(), colorValues[ndx].y(), colorValues[ndx].z(), colorValues[ndx].w())); |
| GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT)); |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| char tmp[4]={"0"}; |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)tmp)); |
| tcu::clear(tcu::getSubregion(reference.getLevel(0), 0, 0, size.x(), size.y()), tcu::Vec4(tmp[0]/(255.0f), tmp[1]/(255.0f), tmp[2]/(255.0f), tmp[3]/(255.0f))); |
| } |
| GLU_CHECK_GLW_CALL(gl, disable(GL_SCISSOR_TEST)); |
| GLU_CHECK_GLW_CALL(gl, framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, 0, 0)); |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0)); |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| } |
| |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); |
| |
| const char* const 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* const fragmentShader = |
| "#extension GL_OES_EGL_image_external : require\n" |
| "varying mediump vec2 v_texCoord;\n" |
| "uniform samplerExternalOES u_sampler;\n" |
| "void main(void) {\n" |
| "\tmediump vec4 texColor = texture2D(u_sampler, v_texCoord);\n" |
| "\tgl_FragColor = vec4(texColor);\n" |
| "}"; |
| |
| Program program(gl, vertexShader, fragmentShader); |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); |
| |
| GLuint samplerLoc = gl.getUniformLocation(glProgram, "u_sampler"); |
| TCU_CHECK_MSG((int)samplerLoc != (int)-1, "Couldn't find uniform u_sampler"); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, *srcTex)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc, 0)); |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, 0)); |
| |
| tcu::Surface refSurface (reference.getWidth(), reference.getHeight()); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr())); |
| |
| tcu::copy(refSurface.getAccess(), reference.getLevel(0)); |
| |
| float threshold = 0.05f; |
| bool match = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface, screen, threshold, tcu::COMPARE_LOG_RESULT); |
| |
| return match; |
| } |
| |
| bool GLESImageApi::RenderExternalTextureSamplerArray::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Texture srcTex (gl); |
| |
| // Branch only taken in TryAll case |
| if (reference.getFormat().order == tcu::TextureFormat::DS || reference.getFormat().order == tcu::TextureFormat::D) |
| throw IllegalRendererException(); // Skip, GLES2 does not support sampling depth textures |
| if (reference.getFormat().order == tcu::TextureFormat::S) |
| throw IllegalRendererException(); // Skip, GLES2 does not support sampling stencil textures |
| |
| gl.clearColor(0.0, 0.0, 0.0, 0.0); |
| gl.viewport(0, 0, reference.getWidth(), reference.getHeight()); |
| gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); |
| gl.disable(GL_DEPTH_TEST); |
| |
| log << tcu::TestLog::Message << "Rendering EGLImage as GL_TEXTURE_EXTERNAL_OES using sampler array in context: " << api.m_contextId << tcu::TestLog::EndMessage; |
| TCU_CHECK(**img != EGL_NO_IMAGE_KHR); |
| |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, *srcTex)); |
| imageTargetExternalTexture(api.m_egl, gl, **img); |
| |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); |
| GLU_CHECK_GLW_CALL(gl, texParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); |
| |
| // Texture not associated with an external texture will return (0, 0, 0, 1) when sampled. |
| GLuint emptyTex; |
| gl.genTextures(1, &emptyTex); |
| gl.activeTexture(GL_TEXTURE1); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, emptyTex)); |
| |
| const char* const 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* const fragmentShader = |
| "#extension GL_OES_EGL_image_external : require\n" |
| "varying mediump vec2 v_texCoord;\n" |
| "uniform samplerExternalOES u_sampler[4];\n" |
| "void main(void) {\n" |
| "\tmediump vec4 texColor = texture2D(u_sampler[2], v_texCoord);\n" |
| "\t//These will sample (0, 0, 0, 1) and should not affect the results.\n" |
| "\ttexColor += texture2D(u_sampler[0], v_texCoord) - vec4(0, 0, 0, 1);\n" |
| "\ttexColor += texture2D(u_sampler[1], v_texCoord) - vec4(0, 0, 0, 1);\n" |
| "\ttexColor += texture2D(u_sampler[3], v_texCoord) - vec4(0, 0, 0, 1);\n" |
| "\tgl_FragColor = vec4(texColor);\n" |
| "}"; |
| |
| Program program(gl, vertexShader, fragmentShader); |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); |
| |
| GLuint samplerLoc0 = gl.getUniformLocation(glProgram, "u_sampler[0]"); |
| TCU_CHECK_MSG((int)samplerLoc0 != (int)-1, "Couldn't find uniform u_sampler[0]"); |
| GLuint samplerLoc1 = gl.getUniformLocation(glProgram, "u_sampler[1]"); |
| TCU_CHECK_MSG((int)samplerLoc1 != (int)-1, "Couldn't find uniform u_sampler[1]"); |
| GLuint samplerLoc2 = gl.getUniformLocation(glProgram, "u_sampler[2]"); |
| TCU_CHECK_MSG((int)samplerLoc2 != (int)-1, "Couldn't find uniform u_sampler[2]"); |
| GLuint samplerLoc3 = gl.getUniformLocation(glProgram, "u_sampler[3]"); |
| TCU_CHECK_MSG((int)samplerLoc3 != (int)-1, "Couldn't find uniform u_sampler[3]"); |
| |
| gl.activeTexture(GL_TEXTURE0); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, *srcTex)); |
| // One sampler reads a gradient and others opaque black. |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc0, 1)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc1, 1)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc2, 0)); |
| GLU_CHECK_GLW_CALL(gl, uniform1i(samplerLoc3, 1)); |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, 0)); |
| gl.activeTexture(GL_TEXTURE1); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_EXTERNAL_OES, 0)); |
| gl.deleteTextures(1, &emptyTex); |
| gl.activeTexture(GL_TEXTURE0); |
| |
| tcu::Surface refSurface (reference.getWidth(), reference.getHeight()); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr())); |
| |
| tcu::copy(refSurface.getAccess(), reference.getLevel(0)); |
| |
| float threshold = 0.05f; |
| bool match = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refSurface, screen, threshold, tcu::COMPARE_LOG_RESULT); |
| |
| return match; |
| } |
| |
| bool GLESImageApi::RenderDepthbuffer::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Framebuffer framebuffer (gl); |
| Renderbuffer renderbufferColor (gl); |
| Renderbuffer renderbufferDepth (gl); |
| const tcu::RGBA compareThreshold (32, 32, 32, 32); // layer colors are far apart, large thresholds are ok |
| |
| // Branch only taken in TryAll case |
| if (reference.getFormat().order != tcu::TextureFormat::DS && reference.getFormat().order != tcu::TextureFormat::D) |
| throw IllegalRendererException(); // Skip, interpreting non-depth data as depth data is not meaningful |
| |
| log << tcu::TestLog::Message << "Rendering with depth buffer" << tcu::TestLog::EndMessage; |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer)); |
| |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferColor)); |
| GLU_CHECK_GLW_CALL(gl, renderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, reference.getWidth(), reference.getHeight())); |
| framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, *renderbufferColor); |
| |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferDepth)); |
| imageTargetRenderbuffer(api.m_egl, gl, **img); |
| framebufferRenderbuffer(gl, GL_DEPTH_ATTACHMENT, *renderbufferDepth); |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0)); |
| |
| GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight())); |
| |
| // 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(gl, vertexShader, fragmentShader); |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); |
| |
| GLuint colorLoc = gl.getUniformLocation(glProgram, "u_color"); |
| TCU_CHECK_MSG((int)colorLoc != (int)-1, "Couldn't find uniform u_color"); |
| |
| GLuint depthLoc = gl.getUniformLocation(glProgram, "u_depth"); |
| TCU_CHECK_MSG((int)depthLoc != (int)-1, "Couldn't find uniform u_depth"); |
| |
| GLU_CHECK_GLW_CALL(gl, clearColor(0.5f, 1.0f, 0.5f, 1.0f)); |
| GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT)); |
| |
| 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) |
| }; |
| |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, enable(GL_DEPTH_TEST)); |
| GLU_CHECK_GLW_CALL(gl, depthFunc(GL_LESS)); |
| GLU_CHECK_GLW_CALL(gl, depthMask(GL_FALSE)); |
| |
| for (int level = 0; level < DE_LENGTH_OF_ARRAY(depthLevelColors); level++) |
| { |
| const tcu::Vec4 color = depthLevelColors[level]; |
| const float clipDepth = ((float)(level + 1) * 0.1f) * 2.0f - 1.0f; // depth in clip coords |
| |
| GLU_CHECK_GLW_CALL(gl, uniform4f(colorLoc, color.x(), color.y(), color.z(), color.w())); |
| GLU_CHECK_GLW_CALL(gl, uniform1f(depthLoc, clipDepth)); |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| } |
| |
| GLU_CHECK_GLW_CALL(gl, depthMask(GL_TRUE)); |
| GLU_CHECK_GLW_CALL(gl, disable(GL_DEPTH_TEST)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| |
| const ConstPixelBufferAccess& refAccess = reference.getLevel(0); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| tcu::Surface referenceScreen (reference.getWidth(), reference.getHeight()); |
| |
| gl.readPixels(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 result = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f); |
| |
| for (int level = 0; level < DE_LENGTH_OF_ARRAY(depthLevelColors); level++) |
| { |
| if ((float)(level + 1) * 0.1f < refAccess.getPixDepth(x, y)) |
| result = depthLevelColors[level]; |
| } |
| |
| referenceScreen.getAccess().setPixel(result, x, y); |
| } |
| } |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0)); |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| |
| return tcu::pixelThresholdCompare(log, "Depth buffer rendering result", "Result from rendering with depth buffer", referenceScreen, screen, compareThreshold, tcu::COMPARE_LOG_RESULT); |
| } |
| |
| bool GLESImageApi::RenderStencilbuffer::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| // Branch only taken in TryAll case |
| if (reference.getFormat().order != tcu::TextureFormat::DS && reference.getFormat().order != tcu::TextureFormat::S) |
| throw IllegalRendererException(); // Skip, interpreting non-stencil data as stencil data is not meaningful |
| |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| Framebuffer framebuffer (gl); |
| Renderbuffer renderbufferColor (gl); |
| Renderbuffer renderbufferStencil (gl); |
| const tcu::RGBA compareThreshold (32, 32, 32, 32); // layer colors are far apart, large thresholds are ok |
| const deUint32 numStencilBits = tcu::getTextureFormatBitDepth(tcu::getEffectiveDepthStencilTextureFormat(reference.getLevel(0).getFormat(), tcu::Sampler::MODE_STENCIL)).x(); |
| const deUint32 maxStencil = deBitMask32(0, numStencilBits); |
| |
| log << tcu::TestLog::Message << "Rendering with stencil buffer" << tcu::TestLog::EndMessage; |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer)); |
| |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferColor)); |
| GLU_CHECK_GLW_CALL(gl, renderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, reference.getWidth(), reference.getHeight())); |
| framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, *renderbufferColor); |
| |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbufferStencil)); |
| imageTargetRenderbuffer(api.m_egl, gl, **img); |
| framebufferRenderbuffer(gl, GL_STENCIL_ATTACHMENT, *renderbufferStencil); |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0)); |
| |
| GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight())); |
| |
| // Render |
| const char* vertexShader = |
| "attribute highp vec2 a_coord;\n" |
| "void main(void) {\n" |
| "\tgl_Position = vec4(a_coord, 0.0, 1.0);\n" |
| "}\n"; |
| |
| const char* fragmentShader = |
| "uniform mediump vec4 u_color;\n" |
| "void main(void) {\n" |
| "\tgl_FragColor = u_color;\n" |
| "}"; |
| |
| Program program(gl, vertexShader, fragmentShader); |
| TCU_CHECK(program.isOk()); |
| |
| GLuint glProgram = program.getProgram(); |
| GLU_CHECK_GLW_CALL(gl, useProgram(glProgram)); |
| |
| GLuint coordLoc = gl.getAttribLocation(glProgram, "a_coord"); |
| TCU_CHECK_MSG((int)coordLoc != -1, "Couldn't find attribute a_coord"); |
| |
| GLuint colorLoc = gl.getUniformLocation(glProgram, "u_color"); |
| TCU_CHECK_MSG((int)colorLoc != (int)-1, "Couldn't find uniform u_color"); |
| |
| GLU_CHECK_GLW_CALL(gl, clearColor(0.5f, 1.0f, 0.5f, 1.0f)); |
| GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT)); |
| |
| tcu::Vec4 stencilLevelColors[] = { |
| 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) |
| }; |
| |
| GLU_CHECK_GLW_CALL(gl, enableVertexAttribArray(coordLoc)); |
| GLU_CHECK_GLW_CALL(gl, vertexAttribPointer(coordLoc, 2, GL_FLOAT, GL_FALSE, 0, squareTriangleCoords)); |
| |
| GLU_CHECK_GLW_CALL(gl, enable(GL_STENCIL_TEST)); |
| GLU_CHECK_GLW_CALL(gl, stencilOp(GL_KEEP, GL_KEEP, GL_KEEP)); |
| |
| for (int level = 0; level < DE_LENGTH_OF_ARRAY(stencilLevelColors); level++) |
| { |
| const tcu::Vec4 color = stencilLevelColors[level]; |
| const int stencil = (int)(((float)(level + 1) * 0.1f) * (float)maxStencil); |
| |
| GLU_CHECK_GLW_CALL(gl, stencilFunc(GL_LESS, stencil, 0xFFFFFFFFu)); |
| GLU_CHECK_GLW_CALL(gl, uniform4f(colorLoc, color.x(), color.y(), color.z(), color.w())); |
| GLU_CHECK_GLW_CALL(gl, drawArrays(GL_TRIANGLES, 0, 6)); |
| } |
| |
| GLU_CHECK_GLW_CALL(gl, disable(GL_STENCIL_TEST)); |
| GLU_CHECK_GLW_CALL(gl, disableVertexAttribArray(coordLoc)); |
| |
| const ConstPixelBufferAccess& refAccess = reference.getLevel(0); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| tcu::Surface referenceScreen (reference.getWidth(), reference.getHeight()); |
| |
| gl.readPixels(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 result = tcu::Vec4(0.5f, 1.0f, 0.5f, 1.0f); |
| |
| for (int level = 0; level < DE_LENGTH_OF_ARRAY(stencilLevelColors); level++) |
| { |
| const int levelStencil = (int)(((float)(level + 1) * 0.1f) * (float)maxStencil); |
| if (levelStencil < refAccess.getPixStencil(x, y)) |
| result = stencilLevelColors[level]; |
| } |
| |
| referenceScreen.getAccess().setPixel(result, x, y); |
| } |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0)); |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| |
| return tcu::pixelThresholdCompare(log, "StencilResult", "Result from rendering with stencil buffer", referenceScreen, screen, compareThreshold, tcu::COMPARE_LOG_RESULT); |
| } |
| |
| bool GLESImageApi::RenderReadPixelsRenderbuffer::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| switch (glu::getInternalFormat(reference.getFormat())) |
| { |
| case GL_RGBA4: |
| case GL_RGB5_A1: |
| case GL_RGB565: |
| break; |
| default: |
| // Skip, not in the list of allowed render buffer formats for GLES. |
| throw tcu::NotSupportedError("Image format not allowed for glReadPixels."); |
| } |
| |
| const glw::Functions& gl = api.m_gl; |
| const tcu::IVec4 bitDepth = tcu::getTextureFormatMantissaBitDepth(reference.getFormat()); |
| const tcu::IVec4 threshold (2 * (tcu::IVec4(1) << (tcu::IVec4(8) - bitDepth))); |
| const tcu::RGBA threshold8 ((deUint8)(de::clamp(threshold[0], 0, 255)), (deUint8)(de::clamp(threshold[1], 0, 255)), (deUint8)(de::clamp(threshold[2], 0, 255)), (deUint8)(de::clamp(threshold[3], 0, 255))); |
| tcu::TestLog& log = api.getLog(); |
| Framebuffer framebuffer (gl); |
| Renderbuffer renderbuffer (gl); |
| tcu::Surface screen (reference.getWidth(), reference.getHeight()); |
| tcu::Surface refSurface (reference.getWidth(), reference.getHeight()); |
| |
| log << tcu::TestLog::Message << "Reading with ReadPixels from renderbuffer" << tcu::TestLog::EndMessage; |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer)); |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer)); |
| imageTargetRenderbuffer(api.m_egl, gl, **img); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "imageTargetRenderbuffer"); |
| framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, *renderbuffer); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferRenderbuffer"); |
| |
| GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight())); |
| |
| GLU_CHECK_GLW_CALL(gl, readPixels(0, 0, screen.getWidth(), screen.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen.getAccess().getDataPtr())); |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0)); |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0)); |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| |
| tcu::copy(refSurface.getAccess(), reference.getLevel(0)); |
| |
| return tcu::pixelThresholdCompare(log, "Renderbuffer read", "Result from reading renderbuffer", refSurface, screen, threshold8, tcu::COMPARE_LOG_RESULT); |
| |
| } |
| |
| bool GLESImageApi::RenderTryAll::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| bool foundSupported = false; |
| tcu::TestLog& log = api.getLog(); |
| GLESImageApi::RenderTexture2D renderTex2D; |
| GLESImageApi::RenderExternalTexture renderExternal; |
| GLESImageApi::RenderExternalTextureSamplerArray renderExternalSamplerArray; |
| GLESImageApi::RenderReadPixelsRenderbuffer renderReadPixels; |
| GLESImageApi::RenderDepthbuffer renderDepth; |
| GLESImageApi::RenderStencilbuffer renderStencil; |
| Action* actions[] = { &renderTex2D, &renderExternal, &renderExternalSamplerArray, &renderReadPixels, &renderDepth, &renderStencil }; |
| set<string> exts = getSupportedExtensions(log, api.m_egl, api.m_display, api.m_gl); |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(actions); ++ndx) |
| { |
| try |
| { |
| const string ext = actions[ndx]->getRequiredExtension(); |
| |
| if (!de::contains(exts, ext)) |
| TCU_THROW_EXPR(NotSupportedError, "Extension not supported", ext.c_str()); |
| |
| if (!actions[ndx]->invoke(api, img, reference)) |
| return false; |
| |
| foundSupported = true; |
| } |
| catch (const tcu::NotSupportedError& error) |
| { |
| log << tcu::TestLog::Message << error.what() << tcu::TestLog::EndMessage; |
| } |
| catch (const IllegalRendererException&) |
| { |
| // not valid renderer |
| } |
| } |
| |
| if (!foundSupported) |
| throw tcu::NotSupportedError("Rendering not supported", "", __FILE__, __LINE__); |
| |
| return true; |
| } |
| |
| bool GLESImageApi::ModifyTexSubImage::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| glu::Texture srcTex (gl); |
| const int xOffset = 8; |
| const int yOffset = 16; |
| const int xSize = de::clamp(16, 0, reference.getWidth() - xOffset); |
| const int ySize = de::clamp(16, 0, reference.getHeight() - yOffset); |
| tcu::Texture2D src (glu::mapGLTransferFormat(m_format, m_type), xSize, ySize); |
| |
| log << tcu::TestLog::Message << "Modifying EGLImage with gl.texSubImage2D" << tcu::TestLog::EndMessage; |
| |
| 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_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, *srcTex)); |
| imageTargetTexture2D(api.m_egl, gl, **img); |
| GLU_CHECK_GLW_CALL(gl, texSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, src.getWidth(), src.getHeight(), m_format, m_type, src.getLevel(0).getDataPtr())); |
| GLU_CHECK_GLW_CALL(gl, bindTexture(GL_TEXTURE_2D, 0)); |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| |
| tcu::copy(tcu::getSubregion(reference.getLevel(0), xOffset, yOffset, 0, xSize, ySize, 1), src.getLevel(0)); |
| |
| return true; |
| } |
| |
| bool GLESImageApi::ModifyRenderbuffer::invokeGLES (GLESImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| tcu::TestLog& log = api.getLog(); |
| glu::Framebuffer framebuffer (gl); |
| glu::Renderbuffer renderbuffer (gl); |
| |
| log << tcu::TestLog::Message << "Modifying EGLImage with glClear to renderbuffer" << tcu::TestLog::EndMessage; |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, *framebuffer)); |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, *renderbuffer)); |
| |
| imageTargetRenderbuffer(api.m_egl, gl, **img); |
| |
| initializeRbo(api, *renderbuffer, reference); |
| |
| GLU_CHECK_GLW_CALL(gl, bindFramebuffer(GL_FRAMEBUFFER, 0)); |
| GLU_CHECK_GLW_CALL(gl, bindRenderbuffer(GL_RENDERBUFFER, 0)); |
| |
| GLU_CHECK_GLW_CALL(gl, finish()); |
| |
| return true; |
| } |
| |
| void GLESImageApi::ModifyRenderbufferClearColor::initializeRbo (GLESImageApi& api, GLuint renderbuffer, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| |
| framebufferRenderbuffer(gl, GL_COLOR_ATTACHMENT0, renderbuffer); |
| |
| GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight())); |
| GLU_CHECK_GLW_CALL(gl, clearColor(m_color.x(), m_color.y(), m_color.z(), m_color.w())); |
| GLU_CHECK_GLW_CALL(gl, clear(GL_COLOR_BUFFER_BIT)); |
| |
| tcu::clear(reference.getLevel(0), m_color); |
| } |
| |
| void GLESImageApi::ModifyRenderbufferClearDepth::initializeRbo (GLESImageApi& api, GLuint renderbuffer, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| |
| framebufferRenderbuffer(gl, GL_DEPTH_ATTACHMENT, renderbuffer); |
| |
| GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight())); |
| GLU_CHECK_GLW_CALL(gl, clearDepthf(m_depth)); |
| GLU_CHECK_GLW_CALL(gl, clear(GL_DEPTH_BUFFER_BIT)); |
| |
| tcu::clearDepth(reference.getLevel(0), m_depth); |
| } |
| |
| void GLESImageApi::ModifyRenderbufferClearStencil::initializeRbo (GLESImageApi& api, GLuint renderbuffer, tcu::Texture2D& reference) const |
| { |
| const glw::Functions& gl = api.m_gl; |
| |
| framebufferRenderbuffer(gl, GL_STENCIL_ATTACHMENT, renderbuffer); |
| |
| GLU_CHECK_GLW_CALL(gl, viewport(0, 0, reference.getWidth(), reference.getHeight())); |
| GLU_CHECK_GLW_CALL(gl, clearStencil(m_stencil)); |
| GLU_CHECK_GLW_CALL(gl, clear(GL_STENCIL_BUFFER_BIT)); |
| |
| tcu::clearStencil(reference.getLevel(0), m_stencil); |
| } |
| |
| class ImageFormatCase : public TestCase, private glu::CallLogWrapper |
| { |
| 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; |
| |
| vector<ImageApi*> m_apiContexts; |
| |
| EGLDisplay m_display; |
| eglu::NativeWindow* m_window; |
| EGLSurface m_surface; |
| EGLConfig m_config; |
| int m_curIter; |
| MovePtr<UniqueImage> m_img; |
| tcu::Texture2D m_refImg; |
| glw::Functions m_gl; |
| }; |
| |
| EGLConfig ImageFormatCase::getConfig (void) |
| { |
| const GLint glesApi = m_spec.contexts[0] == TestSpec::API_GLES3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT; |
| const EGLint attribList[] = |
| { |
| EGL_RENDERABLE_TYPE, glesApi, |
| EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| EGL_RED_SIZE, 8, |
| EGL_BLUE_SIZE, 8, |
| EGL_GREEN_SIZE, 8, |
| EGL_ALPHA_SIZE, 8, |
| EGL_DEPTH_SIZE, 8, |
| EGL_NONE |
| }; |
| |
| return eglu::chooseSingleConfig(m_eglTestCtx.getLibrary(), m_display, attribList); |
| } |
| |
| ImageFormatCase::ImageFormatCase (EglTestContext& eglTestCtx, const TestSpec& spec) |
| : TestCase (eglTestCtx, spec.name.c_str(), spec.desc.c_str()) |
| , glu::CallLogWrapper (m_gl, eglTestCtx.getTestContext().getLog()) |
| , m_spec (spec) |
| , m_display (EGL_NO_DISPLAY) |
| , m_window (DE_NULL) |
| , m_surface (EGL_NO_SURFACE) |
| , m_config (0) |
| , m_curIter (0) |
| , m_refImg (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1) |
| { |
| } |
| |
| ImageFormatCase::~ImageFormatCase (void) |
| { |
| deinit(); |
| } |
| |
| void ImageFormatCase::checkExtensions (void) |
| { |
| set<string> exts = getSupportedExtensions(getLog(), m_eglTestCtx.getLibrary(), m_display, m_gl); |
| |
| for (int operationNdx = 0; operationNdx < (int)m_spec.operations.size(); operationNdx++) |
| { |
| const TestSpec::Operation& op = m_spec.operations[operationNdx]; |
| const string ext = op.action->getRequiredExtension(); |
| |
| if (!de::contains(exts, ext)) |
| TCU_THROW_EXPR(NotSupportedError, "Extension not supported", ext.c_str()); |
| } |
| } |
| |
| void ImageFormatCase::init (void) |
| { |
| const Library& egl = m_eglTestCtx.getLibrary(); |
| const eglu::NativeWindowFactory& windowFactory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine()); |
| |
| try |
| { |
| m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); |
| |
| // GLES3 requires either EGL 1.5 or EGL_KHR_create_context extension. |
| if (m_spec.contexts[0] == TestSpec::API_GLES3 && eglu::getVersion(egl, m_display) < eglu::Version(1, 5)) |
| { |
| set<string> exts; |
| const vector<string> eglExts = eglu::getDisplayExtensions(egl, m_display); |
| exts.insert(eglExts.begin(), eglExts.end()); |
| |
| if (!de::contains(exts, "EGL_KHR_create_context")) |
| { |
| getLog() << tcu::TestLog::Message |
| << "EGL version is under 1.5 and the test is using OpenGL ES 3.2." |
| << "This requires EGL_KHR_create_context extension." |
| << tcu::TestLog::EndMessage; |
| TCU_THROW(NotSupportedError, "Extension not supported: EGL_KHR_create_context"); |
| } |
| } |
| |
| m_config = getConfig(); |
| m_window = windowFactory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_display, m_config, DE_NULL, eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine()))); |
| m_surface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_display, m_config, DE_NULL); |
| |
| { |
| const char* extensions[] = { "GL_OES_EGL_image" }; |
| int major = 2; |
| int minor = 0; |
| |
| if (m_spec.contexts[0] == TestSpec::API_GLES3) |
| { |
| major = 3; |
| minor = 2; |
| } |
| m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(major, minor), DE_LENGTH_OF_ARRAY(extensions), &extensions[0]); |
| } |
| |
| 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 GLESImageApi(egl, m_gl, contextNdx, getLog(), m_display, m_surface, m_config, 2); |
| break; |
| } |
| |
| case TestSpec::API_GLES3: |
| { |
| api = new GLESImageApi(egl, m_gl, contextNdx, getLog(), m_display, m_surface, m_config, 3); |
| break; |
| } |
| |
| default: |
| DE_ASSERT(false); |
| break; |
| } |
| m_apiContexts.push_back(api); |
| } |
| checkExtensions(); |
| } |
| catch (...) |
| { |
| deinit(); |
| throw; |
| } |
| } |
| |
| void ImageFormatCase::deinit (void) |
| { |
| const Library& egl = m_eglTestCtx.getLibrary(); |
| |
| m_img.clear(); |
| |
| for (int contexNdx = 0 ; contexNdx < (int)m_apiContexts.size(); contexNdx++) |
| delete m_apiContexts[contexNdx]; |
| |
| m_apiContexts.clear(); |
| |
| if (m_surface != EGL_NO_SURFACE) |
| { |
| egl.destroySurface(m_display, m_surface); |
| m_surface = EGL_NO_SURFACE; |
| } |
| |
| delete m_window; |
| m_window = DE_NULL; |
| |
| if (m_display != EGL_NO_DISPLAY) |
| { |
| egl.terminate(m_display); |
| m_display = EGL_NO_DISPLAY; |
| } |
| } |
| |
| TestCase::IterateResult ImageFormatCase::iterate (void) |
| { |
| const TestSpec::Operation& op = m_spec.operations[m_curIter++]; |
| ImageApi& api = *m_apiContexts[op.apiIndex]; |
| const bool isOk = op.action->invoke(api, m_img, m_refImg); |
| |
| if (isOk && m_curIter < (int)m_spec.operations.size()) |
| return CONTINUE; |
| else if (isOk) |
| m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); |
| else |
| m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); |
| |
| return STOP; |
| } |
| |
| struct LabeledAction |
| { |
| string label; |
| MovePtr<Action> action; |
| }; |
| |
| // A simple vector mockup that we need because MovePtr isn't copy-constructible. |
| struct LabeledActions |
| { |
| LabeledActions (void) : m_numActions(0){} |
| LabeledAction& operator[] (int ndx) { DE_ASSERT(0 <= ndx && ndx < m_numActions); return m_actions[ndx]; } |
| void add (const string& label, MovePtr<Action> action); |
| int size (void) const { return m_numActions; } |
| private: |
| LabeledAction m_actions[64]; |
| int m_numActions; |
| }; |
| |
| void LabeledActions::add (const string& label, MovePtr<Action> action) |
| { |
| DE_ASSERT(m_numActions < DE_LENGTH_OF_ARRAY(m_actions)); |
| m_actions[m_numActions].label = label; |
| m_actions[m_numActions].action = action; |
| ++m_numActions; |
| } |
| |
| class ImageTests : public TestCaseGroup |
| { |
| protected: |
| ImageTests (EglTestContext& eglTestCtx, const string& name, const string& desc) |
| : TestCaseGroup(eglTestCtx, name.c_str(), desc.c_str()) {} |
| |
| void addCreateTexture (const string& name, EGLenum source, GLenum internalFormat, GLenum format, GLenum type); |
| void addCreateRenderbuffer (const string& name, GLenum format); |
| void addCreateAndroidNative (const string& name, GLenum format, bool isYUV); |
| void addCreateAndroidNativeArray (const string& name, GLenum format, deUint32 numLayers); |
| void addCreateTexture2DActions (const string& prefix); |
| void addCreateTextureCubemapActions (const string& suffix, GLenum internalFormat, GLenum format, GLenum type); |
| void addCreateRenderbufferActions (void); |
| void addCreateAndroidNativeActions (void); |
| |
| LabeledActions m_createActions; |
| }; |
| |
| void ImageTests::addCreateTexture (const string& name, EGLenum source, GLenum internalFormat, GLenum format, GLenum type) |
| { |
| m_createActions.add(name, MovePtr<Action>(new GLESImageApi::Create(createTextureImageSource(source, internalFormat, format, type)))); |
| } |
| |
| void ImageTests::addCreateRenderbuffer (const string& name, GLenum format) |
| { |
| m_createActions.add(name, MovePtr<Action>(new GLESImageApi::Create(createRenderbufferImageSource(format)))); |
| } |
| |
| void ImageTests::addCreateAndroidNative (const string& name, GLenum format, bool isYUV = false) |
| { |
| m_createActions.add(name, MovePtr<Action>(new GLESImageApi::Create(createAndroidNativeImageSource(format, 1u, isYUV)))); |
| } |
| |
| void ImageTests::addCreateAndroidNativeArray (const string& name, GLenum format, deUint32 numLayers) |
| { |
| m_createActions.add(name, MovePtr<Action>(new GLESImageApi::Create(createAndroidNativeImageSource(format, numLayers, false), numLayers))); |
| } |
| |
| void ImageTests::addCreateTexture2DActions (const string& prefix) |
| { |
| addCreateTexture(prefix + "rgb8", EGL_GL_TEXTURE_2D_KHR, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE); |
| addCreateTexture(prefix + "rgb565", EGL_GL_TEXTURE_2D_KHR, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); |
| addCreateTexture(prefix + "rgba8", EGL_GL_TEXTURE_2D_KHR, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); |
| addCreateTexture(prefix + "rgb5_a1", EGL_GL_TEXTURE_2D_KHR, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1); |
| addCreateTexture(prefix + "rgba4", EGL_GL_TEXTURE_2D_KHR, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4); |
| } |
| |
| void ImageTests::addCreateTextureCubemapActions (const string& suffix, GLenum internalFormat, GLenum format, GLenum type) |
| { |
| addCreateTexture("cubemap_positive_x" + suffix, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, internalFormat, format, type); |
| addCreateTexture("cubemap_positive_y" + suffix, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR, internalFormat, format, type); |
| addCreateTexture("cubemap_positive_z" + suffix, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR, internalFormat, format, type); |
| addCreateTexture("cubemap_negative_x" + suffix, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR, internalFormat, format, type); |
| addCreateTexture("cubemap_negative_y" + suffix, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR, internalFormat, format, type); |
| addCreateTexture("cubemap_negative_z" + suffix, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR, internalFormat, format, type); |
| } |
| |
| void ImageTests::addCreateRenderbufferActions (void) |
| { |
| addCreateRenderbuffer("renderbuffer_rgba4", GL_RGBA4); |
| addCreateRenderbuffer("renderbuffer_rgb5_a1", GL_RGB5_A1); |
| addCreateRenderbuffer("renderbuffer_rgb565", GL_RGB565); |
| addCreateRenderbuffer("renderbuffer_depth16", GL_DEPTH_COMPONENT16); |
| addCreateRenderbuffer("renderbuffer_stencil", GL_STENCIL_INDEX8); |
| } |
| |
| void ImageTests::addCreateAndroidNativeActions (void) |
| { |
| addCreateAndroidNative("android_native_rgba4", GL_RGBA4); |
| addCreateAndroidNative("android_native_rgb5_a1", GL_RGB5_A1); |
| addCreateAndroidNative("android_native_rgb565", GL_RGB565); |
| addCreateAndroidNative("android_native_rgb8", GL_RGB8); |
| addCreateAndroidNative("android_native_rgba8", GL_RGBA8); |
| addCreateAndroidNative("android_native_d16", GL_DEPTH_COMPONENT16); |
| addCreateAndroidNative("android_native_d24", GL_DEPTH_COMPONENT24); |
| addCreateAndroidNative("android_native_d24s8", GL_DEPTH24_STENCIL8); |
| addCreateAndroidNative("android_native_d32f", GL_DEPTH_COMPONENT32F); |
| addCreateAndroidNative("android_native_d32fs8", GL_DEPTH32F_STENCIL8); |
| addCreateAndroidNative("android_native_rgb10a2", GL_RGB10_A2); |
| addCreateAndroidNative("android_native_rgba16f", GL_RGBA16F); |
| addCreateAndroidNative("android_native_s8", GL_STENCIL_INDEX8); |
| addCreateAndroidNative("android_native_yuv420", GL_RGBA8, true); |
| |
| addCreateAndroidNativeArray("android_native_array_rgba4", GL_RGBA4, 4u); |
| addCreateAndroidNativeArray("android_native_array_rgb5_a1", GL_RGB5_A1, 4u); |
| addCreateAndroidNativeArray("android_native_array_rgb565", GL_RGB565, 4u); |
| addCreateAndroidNativeArray("android_native_array_rgb8", GL_RGB8, 4u); |
| addCreateAndroidNativeArray("android_native_array_rgba8", GL_RGBA8, 4u); |
| } |
| |
| class RenderTests : public ImageTests |
| { |
| protected: |
| RenderTests (EglTestContext& eglTestCtx, const string& name, const string& desc) |
| : ImageTests (eglTestCtx, name, desc) {} |
| |
| void addRenderActions (void); |
| LabeledActions m_renderActions; |
| }; |
| |
| void RenderTests::addRenderActions (void) |
| { |
| m_renderActions.add("texture", MovePtr<Action>(new GLESImageApi::RenderTexture2D())); |
| m_renderActions.add("texture_array", MovePtr<Action>(new GLESImageApi::RenderTexture2DArray())); |
| m_renderActions.add("read_pixels", MovePtr<Action>(new GLESImageApi::RenderReadPixelsRenderbuffer())); |
| m_renderActions.add("depth_buffer", MovePtr<Action>(new GLESImageApi::RenderDepthbuffer())); |
| m_renderActions.add("stencil_buffer", MovePtr<Action>(new GLESImageApi::RenderStencilbuffer())); |
| m_renderActions.add("yuv_texture", MovePtr<Action>(new GLESImageApi::RenderYUVTexture())); |
| m_renderActions.add("render_sample_texture_array", MovePtr<Action>(new GLESImageApi::RenderSampleTexture2DArray())); |
| } |
| |
| class SimpleCreationTests : public RenderTests |
| { |
| public: |
| SimpleCreationTests (EglTestContext& eglTestCtx, const string& name, const string& desc) : RenderTests(eglTestCtx, name, desc) {} |
| void init (void); |
| }; |
| |
| bool isDepthFormat (GLenum format) |
| { |
| switch (format) |
| { |
| case GL_RGB: |
| case GL_RGB8: |
| case GL_RGB565: |
| case GL_RGBA: |
| case GL_RGBA4: |
| case GL_RGBA8: |
| case GL_RGB5_A1: |
| case GL_RGB10_A2: |
| case GL_RGBA16F: |
| return false; |
| |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT32: |
| case GL_DEPTH_COMPONENT32F: |
| case GL_DEPTH24_STENCIL8: |
| case GL_DEPTH32F_STENCIL8: |
| return true; |
| |
| case GL_STENCIL_INDEX8: |
| return false; |
| |
| default: |
| DE_ASSERT(false); |
| return false; |
| } |
| } |
| |
| bool isStencilFormat (GLenum format) |
| { |
| switch (format) |
| { |
| case GL_RGB: |
| case GL_RGB8: |
| case GL_RGB565: |
| case GL_RGBA: |
| case GL_RGBA4: |
| case GL_RGBA8: |
| case GL_RGB5_A1: |
| case GL_RGB10_A2: |
| case GL_RGBA16F: |
| return false; |
| |
| case GL_DEPTH_COMPONENT16: |
| case GL_DEPTH_COMPONENT24: |
| case GL_DEPTH_COMPONENT32: |
| case GL_DEPTH_COMPONENT32F: |
| return false; |
| |
| case GL_STENCIL_INDEX8: |
| case GL_DEPTH24_STENCIL8: |
| case GL_DEPTH32F_STENCIL8: |
| return true; |
| |
| default: |
| DE_ASSERT(false); |
| return false; |
| } |
| } |
| |
| bool isCompatibleCreateAndRenderActions (const Action& create, const Action& render) |
| { |
| if (const GLESImageApi::Create* glesCreate = dynamic_cast<const GLESImageApi::Create*>(&create)) |
| { |
| bool yuvFormatTest = glesCreate->isYUVFormatImage(); |
| // this path only for none-yuv format tests |
| if(!yuvFormatTest) |
| { |
| const GLenum createFormat = glesCreate->getEffectiveFormat(); |
| |
| if (dynamic_cast<const GLESImageApi::RenderTexture2DArray*>(&render)) |
| { |
| // Makes sense only for texture arrays. |
| if (glesCreate->getNumLayers() <= 1u) |
| return false; |
| } |
| else if (glesCreate->getNumLayers() != 1u) |
| { |
| // Skip other render actions for texture arrays. |
| return false; |
| } |
| |
| if (dynamic_cast<const GLESImageApi::RenderTexture2D*>(&render)) |
| { |
| // GLES does not have depth or stencil textures |
| if (isDepthFormat(createFormat) || isStencilFormat(createFormat)) |
| return false; |
| } |
| |
| if (dynamic_cast<const GLESImageApi::RenderReadPixelsRenderbuffer*>(&render)) |
| { |
| // GLES does not support readPixels for depth or stencil. |
| if (isDepthFormat(createFormat) || isStencilFormat(createFormat)) |
| return false; |
| } |
| |
| if (dynamic_cast<const GLESImageApi::RenderDepthbuffer*>(&render)) |
| { |
| // Copying non-depth data to depth renderbuffer and expecting meaningful |
| // results just doesn't make any sense. |
| if (!isDepthFormat(createFormat)) |
| return false; |
| } |
| |
| if (dynamic_cast<const GLESImageApi::RenderStencilbuffer*>(&render)) |
| { |
| // Copying non-stencil data to stencil renderbuffer and expecting meaningful |
| // results just doesn't make any sense. |
| if (!isStencilFormat(createFormat)) |
| return false; |
| } |
| |
| if (dynamic_cast<const GLESImageApi::RenderYUVTexture*>(&render)) |
| { |
| // In yuv path rendering with non-yuv format native buffer and expecting meaningful |
| // results just doesn't make any sense |
| return false; |
| } |
| |
| return true; |
| } |
| else if (dynamic_cast<const GLESImageApi::RenderYUVTexture*>(&render)) |
| { |
| return true; |
| } |
| } |
| else |
| DE_ASSERT(false); |
| |
| return false; |
| } |
| |
| void SimpleCreationTests::init (void) |
| { |
| addCreateTexture2DActions("texture_"); |
| addCreateTextureCubemapActions("_rgba", GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); |
| addCreateTextureCubemapActions("_rgb", GL_RGB, GL_RGB, GL_UNSIGNED_BYTE); |
| addCreateRenderbufferActions(); |
| addCreateAndroidNativeActions(); |
| addRenderActions(); |
| |
| for (int createNdx = 0; createNdx < m_createActions.size(); createNdx++) |
| { |
| const LabeledAction& createAction = m_createActions[createNdx]; |
| |
| for (int renderNdx = 0; renderNdx < m_renderActions.size(); renderNdx++) |
| { |
| const LabeledAction& renderAction = m_renderActions[renderNdx]; |
| TestSpec spec; |
| |
| if (!isCompatibleCreateAndRenderActions(*createAction.action, *renderAction.action)) |
| continue; |
| |
| if (dynamic_cast<const GLESImageApi::RenderTexture2DArray*>(renderAction.action.get()) || |
| dynamic_cast<const GLESImageApi::RenderYUVTexture*>(renderAction.action.get()) || |
| dynamic_cast<const GLESImageApi::RenderSampleTexture2DArray*>(renderAction.action.get())) |
| { |
| // Texture array tests require GLES3. |
| spec.name = std::string("gles3_") + createAction.label + "_" + renderAction.label; |
| spec.contexts.push_back(TestSpec::API_GLES3); |
| } |
| else |
| { |
| spec.name = std::string("gles2_") + createAction.label + "_" + renderAction.label; |
| spec.contexts.push_back(TestSpec::API_GLES2); |
| } |
| |
| spec.desc = spec.name; |
| spec.operations.push_back(TestSpec::Operation(0, *createAction.action)); |
| spec.operations.push_back(TestSpec::Operation(0, *renderAction.action)); |
| |
| addChild(new ImageFormatCase(m_eglTestCtx, spec)); |
| } |
| } |
| } |
| |
| TestCaseGroup* createSimpleCreationTests (EglTestContext& eglTestCtx, const string& name, const string& desc) |
| { |
| return new SimpleCreationTests(eglTestCtx, name, desc); |
| } |
| |
| bool isCompatibleFormats (GLenum createFormat, GLenum modifyFormat, GLenum modifyType) |
| { |
| switch (modifyFormat) |
| { |
| case GL_RGB: |
| switch (modifyType) |
| { |
| case GL_UNSIGNED_BYTE: |
| return createFormat == GL_RGB |
| || createFormat == GL_RGB8 |
| || createFormat == GL_RGB565 |
| || createFormat == GL_SRGB8; |
| |
| case GL_BYTE: |
| return createFormat == GL_RGB8_SNORM; |
| |
| case GL_UNSIGNED_SHORT_5_6_5: |
| return createFormat == GL_RGB |
| || createFormat == GL_RGB565; |
| |
| case GL_UNSIGNED_INT_10F_11F_11F_REV: |
| return createFormat == GL_R11F_G11F_B10F; |
| |
| case GL_UNSIGNED_INT_5_9_9_9_REV: |
| return createFormat == GL_RGB9_E5; |
| |
| case GL_HALF_FLOAT: |
| return createFormat == GL_RGB16F |
| || createFormat == GL_R11F_G11F_B10F |
| || createFormat == GL_RGB9_E5; |
| |
| case GL_FLOAT: |
| return createFormat == GL_RGB16F |
| || createFormat == GL_RGB32F |
| || createFormat == GL_R11F_G11F_B10F |
| || createFormat == GL_RGB9_E5; |
| |
| default: |
| DE_FATAL("Unknown modify type"); |
| return false; |
| } |
| |
| case GL_RGBA: |
| switch (modifyType) |
| { |
| case GL_UNSIGNED_BYTE: |
| return createFormat == GL_RGBA8 |
| || createFormat == GL_RGB5_A1 |
| || createFormat == GL_RGBA4 |
| || createFormat == GL_SRGB8_ALPHA8 |
| || createFormat == GL_RGBA; |
| |
| case GL_UNSIGNED_SHORT_4_4_4_4: |
| return createFormat == GL_RGBA4 |
| || createFormat == GL_RGBA; |
| |
| case GL_UNSIGNED_SHORT_5_5_5_1: |
| return createFormat == GL_RGB5_A1 |
| || createFormat == GL_RGBA; |
| |
| case GL_UNSIGNED_INT_2_10_10_10_REV: |
| return createFormat == GL_RGB10_A2 |
| || createFormat == GL_RGB5_A1; |
| |
| case GL_HALF_FLOAT: |
| return createFormat == GL_RGBA16F; |
| |
| case GL_FLOAT: |
| return createFormat == GL_RGBA16F |
| || createFormat == GL_RGBA32F; |
| |
| default: |
| DE_FATAL("Unknown modify type"); |
| return false; |
| } |
| |
| default: |
| DE_FATAL("Unknown modify format"); |
| return false; |
| } |
| } |
| |
| bool isCompatibleCreateAndModifyActions (const Action& create, const Action& modify) |
| { |
| if (const GLESImageApi::Create* glesCreate = dynamic_cast<const GLESImageApi::Create*>(&create)) |
| { |
| // No modify tests for texture arrays. |
| if (glesCreate->getNumLayers() > 1u) |
| return false; |
| // No modify tests for yuv format image. |
| if (glesCreate->isYUVFormatImage()) |
| return false; |
| |
| const GLenum createFormat = glesCreate->getEffectiveFormat(); |
| |
| if (const GLESImageApi::ModifyTexSubImage* glesTexSubImageModify = dynamic_cast<const GLESImageApi::ModifyTexSubImage*>(&modify)) |
| { |
| const GLenum modifyFormat = glesTexSubImageModify->getFormat(); |
| const GLenum modifyType = glesTexSubImageModify->getType(); |
| |
| return isCompatibleFormats(createFormat, modifyFormat, modifyType); |
| } |
| |
| if (dynamic_cast<const GLESImageApi::ModifyRenderbufferClearColor*>(&modify)) |
| { |
| // reintepreting color as non-color is not meaningful |
| if (isDepthFormat(createFormat) || isStencilFormat(createFormat)) |
| return false; |
| } |
| |
| if (dynamic_cast<const GLESImageApi::ModifyRenderbufferClearDepth*>(&modify)) |
| { |
| // reintepreting depth as non-depth is not meaningful |
| if (!isDepthFormat(createFormat)) |
| return false; |
| } |
| |
| if (dynamic_cast<const GLESImageApi::ModifyRenderbufferClearStencil*>(&modify)) |
| { |
| // reintepreting stencil as non-stencil is not meaningful |
| if (!isStencilFormat(createFormat)) |
| return false; |
| } |
| |
| return true; |
| } |
| else |
| DE_ASSERT(false); |
| |
| return false; |
| } |
| |
| class MultiContextRenderTests : public RenderTests |
| { |
| public: |
| MultiContextRenderTests (EglTestContext& eglTestCtx, const string& name, const string& desc); |
| void init (void); |
| void addClearActions (void); |
| private: |
| LabeledActions m_clearActions; |
| }; |
| |
| MultiContextRenderTests::MultiContextRenderTests (EglTestContext& eglTestCtx, const string& name, const string& desc) |
| : RenderTests (eglTestCtx, name, desc) |
| { |
| } |
| |
| void MultiContextRenderTests::addClearActions (void) |
| { |
| m_clearActions.add("clear_color", MovePtr<Action>(new GLESImageApi::ModifyRenderbufferClearColor(tcu::Vec4(0.8f, 0.2f, 0.9f, 1.0f)))); |
| m_clearActions.add("clear_depth", MovePtr<Action>(new GLESImageApi::ModifyRenderbufferClearDepth(0.75f))); |
| m_clearActions.add("clear_stencil", MovePtr<Action>(new GLESImageApi::ModifyRenderbufferClearStencil(97))); |
| } |
| |
| void MultiContextRenderTests::init (void) |
| { |
| addCreateTexture2DActions("texture_"); |
| addCreateTextureCubemapActions("_rgba8", GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); |
| addCreateTextureCubemapActions("_rgb8", GL_RGB, GL_RGB, GL_UNSIGNED_BYTE); |
| addCreateRenderbufferActions(); |
| addCreateAndroidNativeActions(); |
| addRenderActions(); |
| addClearActions(); |
| |
| for (int createNdx = 0; createNdx < m_createActions.size(); createNdx++) |
| for (int renderNdx = 0; renderNdx < m_renderActions.size(); renderNdx++) |
| for (int clearNdx = 0; clearNdx < m_clearActions.size(); clearNdx++) |
| { |
| const LabeledAction& createAction = m_createActions[createNdx]; |
| const LabeledAction& renderAction = m_renderActions[renderNdx]; |
| const LabeledAction& clearAction = m_clearActions[clearNdx]; |
| TestSpec spec; |
| |
| if (!isCompatibleCreateAndRenderActions(*createAction.action, *renderAction.action)) |
| continue; |
| if (!isCompatibleCreateAndModifyActions(*createAction.action, *clearAction.action)) |
| continue; |
| |
| spec.name = std::string("gles2_") + createAction.label + "_" + renderAction.label; |
| |
| const GLESImageApi::Create* glesCreate = dynamic_cast<const GLESImageApi::Create*>(createAction.action.get()); |
| |
| if (!glesCreate) |
| DE_FATAL("Dynamic casting to GLESImageApi::Create* failed"); |
| |
| const GLenum createFormat = glesCreate->getEffectiveFormat(); |
| |
| if (isDepthFormat(createFormat) && isStencilFormat(createFormat)) |
| { |
| // Combined depth and stencil format. Add the clear action label to avoid test |
| // name clashes. |
| spec.name += std::string("_") + clearAction.label; |
| } |
| |
| spec.desc = spec.name; |
| |
| spec.contexts.push_back(TestSpec::API_GLES2); |
| spec.contexts.push_back(TestSpec::API_GLES2); |
| |
| spec.operations.push_back(TestSpec::Operation(0, *createAction.action)); |
| spec.operations.push_back(TestSpec::Operation(0, *renderAction.action)); |
| spec.operations.push_back(TestSpec::Operation(0, *clearAction.action)); |
| spec.operations.push_back(TestSpec::Operation(1, *createAction.action)); |
| spec.operations.push_back(TestSpec::Operation(0, *renderAction.action)); |
| spec.operations.push_back(TestSpec::Operation(1, *renderAction.action)); |
| |
| addChild(new ImageFormatCase(m_eglTestCtx, spec)); |
| } |
| } |
| |
| TestCaseGroup* createMultiContextRenderTests (EglTestContext& eglTestCtx, const string& name, const string& desc) |
| { |
| return new MultiContextRenderTests(eglTestCtx, name, desc); |
| } |
| |
| class ModifyTests : public ImageTests |
| { |
| public: |
| ModifyTests (EglTestContext& eglTestCtx, const string& name, const string& desc) |
| : ImageTests(eglTestCtx, name, desc) {} |
| |
| void init (void); |
| |
| protected: |
| void addModifyActions(void); |
| |
| LabeledActions m_modifyActions; |
| GLESImageApi::RenderTryAll m_renderAction; |
| }; |
| |
| void ModifyTests::addModifyActions (void) |
| { |
| m_modifyActions.add("tex_subimage_rgb8", MovePtr<Action>(new GLESImageApi::ModifyTexSubImage(GL_RGB, GL_UNSIGNED_BYTE))); |
| m_modifyActions.add("tex_subimage_rgb565", MovePtr<Action>(new GLESImageApi::ModifyTexSubImage(GL_RGB, GL_UNSIGNED_SHORT_5_6_5))); |
| m_modifyActions.add("tex_subimage_rgba8", MovePtr<Action>(new GLESImageApi::ModifyTexSubImage(GL_RGBA, GL_UNSIGNED_BYTE))); |
| m_modifyActions.add("tex_subimage_rgb5_a1", MovePtr<Action>(new GLESImageApi::ModifyTexSubImage(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1))); |
| m_modifyActions.add("tex_subimage_rgba4", MovePtr<Action>(new GLESImageApi::ModifyTexSubImage(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4))); |
| |
| m_modifyActions.add("renderbuffer_clear_color", MovePtr<Action>(new GLESImageApi::ModifyRenderbufferClearColor(tcu::Vec4(0.3f, 0.5f, 0.3f, 1.0f)))); |
| m_modifyActions.add("renderbuffer_clear_depth", MovePtr<Action>(new GLESImageApi::ModifyRenderbufferClearDepth(0.7f))); |
| m_modifyActions.add("renderbuffer_clear_stencil", MovePtr<Action>(new GLESImageApi::ModifyRenderbufferClearStencil(78))); |
| } |
| |
| void ModifyTests::init (void) |
| { |
| addCreateTexture2DActions("tex_"); |
| addCreateRenderbufferActions(); |
| addCreateAndroidNativeActions(); |
| addModifyActions(); |
| |
| for (int createNdx = 0; createNdx < m_createActions.size(); createNdx++) |
| { |
| LabeledAction& createAction = m_createActions[createNdx]; |
| |
| for (int modifyNdx = 0; modifyNdx < m_modifyActions.size(); modifyNdx++) |
| { |
| LabeledAction& modifyAction = m_modifyActions[modifyNdx]; |
| |
| if (!isCompatibleCreateAndModifyActions(*createAction.action, *modifyAction.action)) |
| continue; |
| |
| TestSpec spec; |
| spec.name = createAction.label + "_" + modifyAction.label; |
| spec.desc = "gles2_tex_sub_image"; |
| |
| spec.contexts.push_back(TestSpec::API_GLES2); |
| |
| spec.operations.push_back(TestSpec::Operation(0, *createAction.action)); |
| spec.operations.push_back(TestSpec::Operation(0, m_renderAction)); |
| spec.operations.push_back(TestSpec::Operation(0, *modifyAction.action)); |
| spec.operations.push_back(TestSpec::Operation(0, m_renderAction)); |
| |
| addChild(new ImageFormatCase(m_eglTestCtx, spec)); |
| } |
| } |
| } |
| |
| TestCaseGroup* createModifyTests (EglTestContext& eglTestCtx, const string& name, const string& desc) |
| { |
| return new ModifyTests(eglTestCtx, name, desc); |
| } |
| |
| } // Image |
| } // egl |
| } // deqp |