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