You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1603 lines
54 KiB
1603 lines
54 KiB
/*-------------------------------------------------------------------------
|
|
* 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_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 GLES2ImageApi : public ImageApi, private glu::CallLogWrapper
|
|
{
|
|
public:
|
|
class GLES2Action : public Action
|
|
{
|
|
public:
|
|
bool invoke (ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const;
|
|
virtual bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const = 0;
|
|
};
|
|
|
|
class Create : public GLES2Action
|
|
{
|
|
public:
|
|
Create (MovePtr<ImageSource> imgSource) : m_imgSource(imgSource) {}
|
|
string getRequiredExtension (void) const { return m_imgSource->getRequiredExtension(); }
|
|
bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const;
|
|
glw::GLenum getEffectiveFormat (void) const { return m_imgSource->getEffectiveFormat(); }
|
|
|
|
private:
|
|
UniquePtr<ImageSource> m_imgSource;
|
|
};
|
|
|
|
class Render : public GLES2Action
|
|
{
|
|
public:
|
|
string getRequiredExtension (void) const { return "GL_OES_EGL_image"; }
|
|
};
|
|
|
|
class RenderTexture2D : public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
|
|
class RenderTextureCubemap : public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
|
|
class RenderReadPixelsRenderbuffer : public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
|
|
class RenderDepthbuffer : public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
|
|
class RenderStencilbuffer : public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
|
|
class RenderTryAll : public Render { public: bool invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const; };
|
|
|
|
class Modify : public GLES2Action
|
|
{
|
|
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 invokeGLES2 (GLES2ImageApi& 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 invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const;
|
|
|
|
protected:
|
|
virtual void initializeRbo (GLES2ImageApi& api, GLuint rbo, tcu::Texture2D& ref) const = 0;
|
|
};
|
|
|
|
class ModifyRenderbufferClearColor : public ModifyRenderbuffer
|
|
{
|
|
public:
|
|
ModifyRenderbufferClearColor (tcu::Vec4 color) : m_color(color) {}
|
|
|
|
protected:
|
|
void initializeRbo (GLES2ImageApi& 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 (GLES2ImageApi& api, GLuint rbo, tcu::Texture2D& ref) const;
|
|
|
|
GLfloat m_depth;
|
|
};
|
|
|
|
class ModifyRenderbufferClearStencil : public ModifyRenderbuffer
|
|
{
|
|
public:
|
|
ModifyRenderbufferClearStencil (GLint stencil) : m_stencil(stencil) {}
|
|
|
|
protected:
|
|
void initializeRbo (GLES2ImageApi& api, GLuint rbo, tcu::Texture2D& ref) const;
|
|
|
|
GLint m_stencil;
|
|
};
|
|
|
|
GLES2ImageApi (const Library& egl, const glw::Functions& gl, int contextId, tcu::TestLog& log, EGLDisplay display, EGLSurface surface, EGLConfig config);
|
|
~GLES2ImageApi (void);
|
|
|
|
private:
|
|
EGLContext m_context;
|
|
const glw::Functions& m_gl;
|
|
|
|
MovePtr<UniqueImage> createImage (const ImageSource& source, const ClientBuffer& buffer) const;
|
|
};
|
|
|
|
GLES2ImageApi::GLES2ImageApi (const Library& egl, const glw::Functions& gl, int contextId, tcu::TestLog& log, EGLDisplay display, EGLSurface surface, EGLConfig config)
|
|
: ImageApi (egl, contextId, display, surface)
|
|
, glu::CallLogWrapper (gl, log)
|
|
, m_context (DE_NULL)
|
|
, m_gl (gl)
|
|
{
|
|
const EGLint attriblist[] =
|
|
{
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
EGL_NONE
|
|
};
|
|
|
|
EGLint configId = -1;
|
|
EGLU_CHECK_CALL(m_egl, getConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId));
|
|
getLog() << tcu::TestLog::Message << "Creating gles2 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 GLES2 context");
|
|
|
|
egl.makeCurrent(display, m_surface, m_surface, m_context);
|
|
EGLU_CHECK_MSG(m_egl, "Failed to make context current");
|
|
}
|
|
|
|
GLES2ImageApi::~GLES2ImageApi (void)
|
|
{
|
|
m_egl.makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
m_egl.destroyContext(m_display, m_context);
|
|
}
|
|
|
|
bool GLES2ImageApi::GLES2Action::invoke (ImageApi& api, MovePtr<UniqueImage>& image, tcu::Texture2D& ref) const
|
|
{
|
|
GLES2ImageApi& gles2Api = dynamic_cast<GLES2ImageApi&>(api);
|
|
|
|
gles2Api.m_egl.makeCurrent(gles2Api.m_display, gles2Api.m_surface, gles2Api.m_surface, gles2Api.m_context);
|
|
return invokeGLES2(gles2Api, image, ref);
|
|
}
|
|
|
|
|
|
bool GLES2ImageApi::Create::invokeGLES2 (GLES2ImageApi& 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> GLES2ImageApi::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 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 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 GLES2ImageApi::RenderTexture2D::invokeGLES2 (GLES2ImageApi& 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_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;
|
|
}
|
|
|
|
bool GLES2ImageApi::RenderDepthbuffer::invokeGLES2 (GLES2ImageApi& 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 GLES2ImageApi::RenderStencilbuffer::invokeGLES2 (GLES2ImageApi& 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 GLES2ImageApi::RenderReadPixelsRenderbuffer::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
|
|
{
|
|
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());
|
|
|
|
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 GLES2.
|
|
throw tcu::NotSupportedError("Image format not allowed for glReadPixels.");
|
|
break;
|
|
}
|
|
|
|
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 GLES2ImageApi::RenderTryAll::invokeGLES2 (GLES2ImageApi& api, MovePtr<UniqueImage>& img, tcu::Texture2D& reference) const
|
|
{
|
|
bool foundSupported = false;
|
|
tcu::TestLog& log = api.getLog();
|
|
GLES2ImageApi::RenderTexture2D renderTex2D;
|
|
GLES2ImageApi::RenderReadPixelsRenderbuffer renderReadPixels;
|
|
GLES2ImageApi::RenderDepthbuffer renderDepth;
|
|
GLES2ImageApi::RenderStencilbuffer renderStencil;
|
|
Action* actions[] = { &renderTex2D, &renderReadPixels, &renderDepth, &renderStencil };
|
|
|
|
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(actions); ++ndx)
|
|
{
|
|
try
|
|
{
|
|
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 GLES2ImageApi::ModifyTexSubImage::invokeGLES2 (GLES2ImageApi& 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 GLES2ImageApi::ModifyRenderbuffer::invokeGLES2 (GLES2ImageApi& 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 GLES2ImageApi::ModifyRenderbufferClearColor::initializeRbo (GLES2ImageApi& 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 GLES2ImageApi::ModifyRenderbufferClearDepth::initializeRbo (GLES2ImageApi& 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 GLES2ImageApi::ModifyRenderbufferClearStencil::initializeRbo (GLES2ImageApi& 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 EGLint attribList[] =
|
|
{
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
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)
|
|
{
|
|
const Library& egl = m_eglTestCtx.getLibrary();
|
|
const EGLDisplay dpy = m_display;
|
|
set<string> exts;
|
|
const vector<string> glExts = de::splitString((const char*) m_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"))
|
|
{
|
|
getLog() << 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");
|
|
}
|
|
|
|
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());
|
|
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" };
|
|
m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2, 0), 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 GLES2ImageApi(egl, m_gl, contextNdx, getLog(), m_display, m_surface, m_config);
|
|
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);
|
|
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 GLES2ImageApi::Create(createTextureImageSource(source, internalFormat, format, type))));
|
|
}
|
|
|
|
void ImageTests::addCreateRenderbuffer (const string& name, GLenum format)
|
|
{
|
|
m_createActions.add(name, MovePtr<Action>(new GLES2ImageApi::Create(createRenderbufferImageSource(format))));
|
|
}
|
|
|
|
void ImageTests::addCreateAndroidNative (const string& name, GLenum format)
|
|
{
|
|
m_createActions.add(name, MovePtr<Action>(new GLES2ImageApi::Create(createAndroidNativeImageSource(format))));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 GLES2ImageApi::RenderTexture2D()));
|
|
m_renderActions.add("read_pixels", MovePtr<Action>(new GLES2ImageApi::RenderReadPixelsRenderbuffer()));
|
|
m_renderActions.add("depth_buffer", MovePtr<Action>(new GLES2ImageApi::RenderDepthbuffer()));
|
|
m_renderActions.add("stencil_buffer", MovePtr<Action>(new GLES2ImageApi::RenderStencilbuffer()));
|
|
}
|
|
|
|
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 GLES2ImageApi::Create* gles2Create = dynamic_cast<const GLES2ImageApi::Create*>(&create))
|
|
{
|
|
const GLenum createFormat = gles2Create->getEffectiveFormat();
|
|
|
|
if (dynamic_cast<const GLES2ImageApi::RenderTexture2D*>(&render))
|
|
{
|
|
// GLES2 does not have depth or stencil textures
|
|
if (isDepthFormat(createFormat) || isStencilFormat(createFormat))
|
|
return false;
|
|
}
|
|
|
|
if (dynamic_cast<const GLES2ImageApi::RenderReadPixelsRenderbuffer*>(&render))
|
|
{
|
|
// GLES2 does not support readPixels for depth or stencil
|
|
if (isDepthFormat(createFormat) || isStencilFormat(createFormat))
|
|
return false;
|
|
}
|
|
|
|
if (dynamic_cast<const GLES2ImageApi::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 GLES2ImageApi::RenderStencilbuffer*>(&render))
|
|
{
|
|
// Copying non-stencil data to stencil renderbuffer and expecting meaningful
|
|
// results just doesn't make any sense.
|
|
if (!isStencilFormat(createFormat))
|
|
return false;
|
|
}
|
|
|
|
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;
|
|
|
|
spec.name = std::string("gles2_") + createAction.label + "_" + renderAction.label;
|
|
spec.desc = spec.name;
|
|
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));
|
|
|
|
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 GLES2ImageApi::Create* gles2Create = dynamic_cast<const GLES2ImageApi::Create*>(&create))
|
|
{
|
|
const GLenum createFormat = gles2Create->getEffectiveFormat();
|
|
|
|
if (const GLES2ImageApi::ModifyTexSubImage* gles2TexSubImageModify = dynamic_cast<const GLES2ImageApi::ModifyTexSubImage*>(&modify))
|
|
{
|
|
const GLenum modifyFormat = gles2TexSubImageModify->getFormat();
|
|
const GLenum modifyType = gles2TexSubImageModify->getType();
|
|
|
|
return isCompatibleFormats(createFormat, modifyFormat, modifyType);
|
|
}
|
|
|
|
if (dynamic_cast<const GLES2ImageApi::ModifyRenderbufferClearColor*>(&modify))
|
|
{
|
|
// reintepreting color as non-color is not meaningful
|
|
if (isDepthFormat(createFormat) || isStencilFormat(createFormat))
|
|
return false;
|
|
}
|
|
|
|
if (dynamic_cast<const GLES2ImageApi::ModifyRenderbufferClearDepth*>(&modify))
|
|
{
|
|
// reintepreting depth as non-depth is not meaningful
|
|
if (!isDepthFormat(createFormat))
|
|
return false;
|
|
}
|
|
|
|
if (dynamic_cast<const GLES2ImageApi::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 GLES2ImageApi::ModifyRenderbufferClearColor(tcu::Vec4(0.8f, 0.2f, 0.9f, 1.0f))));
|
|
m_clearActions.add("clear_depth", MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearDepth(0.75f)));
|
|
m_clearActions.add("clear_stencil", MovePtr<Action>(new GLES2ImageApi::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 GLenum createFormat = dynamic_cast<const GLES2ImageApi::Create*>(createAction.action.get())->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;
|
|
GLES2ImageApi::RenderTryAll m_renderAction;
|
|
};
|
|
|
|
void ModifyTests::addModifyActions (void)
|
|
{
|
|
m_modifyActions.add("tex_subimage_rgb8", MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGB, GL_UNSIGNED_BYTE)));
|
|
m_modifyActions.add("tex_subimage_rgb565", MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGB, GL_UNSIGNED_SHORT_5_6_5)));
|
|
m_modifyActions.add("tex_subimage_rgba8", MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGBA, GL_UNSIGNED_BYTE)));
|
|
m_modifyActions.add("tex_subimage_rgb5_a1", MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1)));
|
|
m_modifyActions.add("tex_subimage_rgba4", MovePtr<Action>(new GLES2ImageApi::ModifyTexSubImage(GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4)));
|
|
|
|
m_modifyActions.add("renderbuffer_clear_color", MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearColor(tcu::Vec4(0.3f, 0.5f, 0.3f, 1.0f))));
|
|
m_modifyActions.add("renderbuffer_clear_depth", MovePtr<Action>(new GLES2ImageApi::ModifyRenderbufferClearDepth(0.7f)));
|
|
m_modifyActions.add("renderbuffer_clear_stencil", MovePtr<Action>(new GLES2ImageApi::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
|