blob: 6656d1e5e597ccbafcb5319b25e6a5dff86f9500 [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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 "teglImageTests.hpp"
#include "teglImageFormatTests.hpp"
#include "egluNativeDisplay.hpp"
#include "egluNativeWindow.hpp"
#include "egluNativePixmap.hpp"
#include "egluStrUtil.hpp"
#include "egluUtil.hpp"
#include "gluDefs.hpp"
#include "gluStrUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuCommandLine.hpp"
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <set>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
using tcu::TestLog;
using std::string;
using std::vector;
using std::set;
namespace deqp
{
namespace egl
{
namespace Image
{
bool checkExtensions (const tcu::egl::Display& dpy, const char** first, const char** last, vector<const char*>& unsupported)
{
vector<string> extensions;
dpy.getExtensions(extensions);
set<string> extSet(extensions.begin(), extensions.end());
unsupported.clear();
for (const char** extIter = first; extIter != last; extIter++)
{
const char* ext = *extIter;
if (extSet.find(ext) == extSet.end())
unsupported.push_back(ext);
}
return unsupported.size() == 0;
}
string join (const vector<const char*>& parts, const char* separator)
{
std::ostringstream str;
for (std::vector<const char*>::const_iterator i = parts.begin(); i != parts.end(); i++)
{
if (i != parts.begin())
str << separator;
str << *i;
}
return str.str();
}
void checkExtensions (const tcu::egl::Display& dpy, const char** first, const char** last)
{
vector<const char*> unsupported;
if (!checkExtensions(dpy, first, last, unsupported))
throw tcu::NotSupportedError("Extension not supported", join(unsupported, " ").c_str(), __FILE__, __LINE__);
}
template <size_t N>
void checkExtensions (const tcu::egl::Display& dpy, const char* (&extensions)[N])
{
checkExtensions(dpy, &extensions[0], &extensions[N]);
}
#define CHECK_EXTENSIONS(EXTENSIONS) do { static const char* ext[] = EXTENSIONS; checkExtensions(m_eglTestCtx.getDisplay(), ext); } while (deGetFalse())
template <typename RetVal>
RetVal checkCallError (tcu::TestContext& testCtx, const char* call, RetVal returnValue, EGLint expectError)
{
TestLog& log = testCtx.getLog();
log << TestLog::Message << call << TestLog::EndMessage;
EGLint error = eglGetError();
if (error != expectError)
{
log << TestLog::Message << " Fail: Error code mismatch! Expected " << eglu::getErrorStr(expectError) << ", got " << eglu::getErrorStr(error) << TestLog::EndMessage;
log << TestLog::Message << " " << returnValue << " was returned" << TestLog::EndMessage;
if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error code");
}
return returnValue;
}
template <typename RetVal>
void checkCallReturn (tcu::TestContext& testCtx, const char* call, RetVal returnValue, RetVal expectReturnValue, EGLint expectError)
{
TestLog& log = testCtx.getLog();
log << TestLog::Message << call << TestLog::EndMessage;
EGLint error = eglGetError();
if (returnValue != expectReturnValue)
{
log << TestLog::Message << " Fail: Return value mismatch! Expected " << expectReturnValue << ", got " << returnValue << TestLog::EndMessage;
if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid return value");
}
if (error != expectError)
{
log << TestLog::Message << " Fail: Error code mismatch! Expected " << eglu::getErrorStr(expectError) << ", got " << eglu::getErrorStr(error) << TestLog::EndMessage;
if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error code");
}
}
void checkGLCall (tcu::TestContext& testCtx, const char* call, GLenum expectError)
{
TestLog& log = testCtx.getLog();
log << TestLog::Message << call << TestLog::EndMessage;
GLenum error = glGetError();
if (error != expectError)
{
log << TestLog::Message << " Fail: Error code mismatch! Expected " << glu::getErrorStr(expectError) << ", got " << glu::getErrorStr(error) << TestLog::EndMessage;
if (testCtx.getTestResult() == QP_TEST_RESULT_PASS)
testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid error code");
}
}
// \note These macros expect "TestContext m_testCtx" and "ExtFuncTable efTable" variables to be defined.
#define CHECK_EXT_CALL_RET(CALL, EXPECT_RETURN_VALUE, EXPECT_ERROR) checkCallReturn(m_testCtx, #CALL, efTable.CALL, (EXPECT_RETURN_VALUE), (EXPECT_ERROR))
#define CHECK_EXT_CALL_ERR(CALL, EXPECT_ERROR) checkCallError(m_testCtx, #CALL, efTable.CALL, (EXPECT_ERROR))
#define CHECK_GL_EXT_CALL(CALL, EXPECT_ERROR) do { efTable.CALL; checkGLCall(m_testCtx, #CALL, (EXPECT_ERROR)); } while (deGetFalse())
class ExtFuncTable
{
public:
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
ExtFuncTable (void)
{
// EGL_KHR_image_base
eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
// OES_EGL_image
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES");
glEGLImageTargetRenderbufferStorageOES = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES");
}
};
class InvalidCreateImage : public TestCase
{
public:
InvalidCreateImage (EglTestContext& eglTestCtx)
: TestCase(eglTestCtx, "invalid_create_image", "eglCreateImageKHR() with invalid arguments")
{
}
IterateResult iterate (void)
{
EGLDisplay dpy = m_eglTestCtx.getDisplay().getEGLDisplay();
TestLog& log = m_testCtx.getLog();
ExtFuncTable efTable;
CHECK_EXTENSIONS({ "EGL_KHR_image_base" });
// Initialize result to pass.
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
log << TestLog::Message << "Testing bad display (-1)..." << TestLog::EndMessage;
CHECK_EXT_CALL_RET(eglCreateImageKHR((EGLDisplay)-1, EGL_NO_CONTEXT, EGL_NONE, 0, DE_NULL),
EGL_NO_IMAGE_KHR, EGL_BAD_DISPLAY);
log << TestLog::Message << "Testing bad context (-1)..." << TestLog::EndMessage;
CHECK_EXT_CALL_RET(eglCreateImageKHR(dpy, (EGLContext)-1, EGL_NONE, 0, DE_NULL),
EGL_NO_IMAGE_KHR, EGL_BAD_CONTEXT);
log << TestLog::Message << "Testing bad parameter (-1).." << TestLog::EndMessage;
CHECK_EXT_CALL_RET(eglCreateImageKHR(dpy, EGL_NO_CONTEXT, (EGLenum)-1, 0, DE_NULL),
EGL_NO_IMAGE_KHR, EGL_BAD_PARAMETER);
return STOP;
}
};
class GLES2Context
{
public:
GLES2Context (EglTestContext& eglTestCtx, EGLint configId, int width, int height)
: m_eglTestCtx (eglTestCtx)
, m_config (getConfigById(eglTestCtx.getDisplay(), configId))
, m_context (eglTestCtx.getDisplay(), m_config, m_ctxAttrs, EGL_OPENGL_ES_API)
, m_window (DE_NULL)
, m_pixmap (DE_NULL)
, m_surface (DE_NULL)
{
tcu::egl::Display& dpy = eglTestCtx.getDisplay();
EGLint surfaceTypeBits = dpy.getConfigAttrib(m_config, EGL_SURFACE_TYPE);
if (surfaceTypeBits & EGL_PBUFFER_BIT)
{
EGLint pbufferAttrs[] =
{
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_NONE
};
m_surface = new tcu::egl::PbufferSurface(dpy, m_config, pbufferAttrs);
}
else if (surfaceTypeBits & EGL_WINDOW_BIT)
{
m_window = eglTestCtx.createNativeWindow(dpy.getEGLDisplay(), m_config, DE_NULL, width, height, eglu::parseWindowVisibility(eglTestCtx.getTestContext().getCommandLine()));
m_surface = new tcu::egl::WindowSurface(dpy, eglu::createWindowSurface(eglTestCtx.getNativeDisplay(), *m_window, dpy.getEGLDisplay(), m_config, DE_NULL));
}
else if (surfaceTypeBits & EGL_PIXMAP_BIT)
{
m_pixmap = eglTestCtx.createNativePixmap(dpy.getEGLDisplay(), m_config, DE_NULL, width, height);
m_surface = new tcu::egl::PixmapSurface(dpy, eglu::createPixmapSurface(eglTestCtx.getNativeDisplay(), *m_pixmap, dpy.getEGLDisplay(), m_config, DE_NULL));
}
else
TCU_FAIL("No valid surface types supported in config");
m_context.makeCurrent(*m_surface, *m_surface);
}
~GLES2Context (void)
{
eglMakeCurrent(m_eglTestCtx.getDisplay().getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
delete m_window;
delete m_pixmap;
delete m_surface;
}
EGLDisplay getEglDisplay (void)
{
return m_eglTestCtx.getDisplay().getEGLDisplay();
}
EGLContext getEglContext (void)
{
return m_context.getEGLContext();
}
// Helper for selecting config.
static EGLint getConfigIdForApi (const vector<eglu::ConfigInfo>& configInfos, EGLint apiBits)
{
EGLint windowCfg = 0;
EGLint pixmapCfg = 0;
EGLint pbufferCfg = 0;
for (vector<eglu::ConfigInfo>::const_iterator cfgIter = configInfos.begin(); cfgIter != configInfos.end(); cfgIter++)
{
if ((cfgIter->renderableType & apiBits) == 0)
continue;
if (windowCfg == 0 && (cfgIter->surfaceType & EGL_WINDOW_BIT) != 0)
windowCfg = cfgIter->configId;
if (pixmapCfg == 0 && (cfgIter->surfaceType & EGL_PIXMAP_BIT) != 0)
pixmapCfg = cfgIter->configId;
if (pbufferCfg == 0 && (cfgIter->surfaceType & EGL_PBUFFER_BIT) != 0)
pbufferCfg = cfgIter->configId;
if (windowCfg && pixmapCfg && pbufferCfg)
break;
}
// Prefer configs in order: pbuffer, window, pixmap
if (pbufferCfg)
return pbufferCfg;
else if (windowCfg)
return windowCfg;
else if (pixmapCfg)
return pixmapCfg;
else
throw tcu::NotSupportedError("No compatible EGL configs found", "", __FILE__, __LINE__);
}
private:
static EGLConfig getConfigById (const tcu::egl::Display& dpy, EGLint configId)
{
EGLint attributes[] = { EGL_CONFIG_ID, configId, EGL_NONE };
vector<EGLConfig> configs;
dpy.chooseConfig(attributes, configs);
TCU_CHECK(configs.size() == 1);
return configs[0];
}
static const EGLint m_ctxAttrs[];
EglTestContext& m_eglTestCtx;
EGLConfig m_config;
tcu::egl::Context m_context;
eglu::NativeWindow* m_window;
eglu::NativePixmap* m_pixmap;
tcu::egl::Surface* m_surface;
GLES2Context (const GLES2Context&);
GLES2Context& operator= (const GLES2Context&);
};
const EGLint GLES2Context::m_ctxAttrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
class CreateImageGLES2 : public TestCase
{
public:
static const char* getTargetName (EGLint target)
{
switch (target)
{
case EGL_GL_TEXTURE_2D_KHR: return "tex2d";
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: return "cubemap_pos_x";
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: return "cubemap_neg_x";
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: return "cubemap_pos_y";
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: return "cubemap_neg_y";
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: return "cubemap_pos_z";
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: return "cubemap_neg_z";
case EGL_GL_RENDERBUFFER_KHR: return "renderbuffer";
default: DE_ASSERT(DE_FALSE); return "";
}
}
static const char* getStorageName (GLenum storage)
{
switch (storage)
{
case GL_RGB: return "rgb";
case GL_RGBA: return "rgba";
case GL_DEPTH_COMPONENT16: return "depth_component_16";
case GL_RGBA4: return "rgba4";
case GL_RGB5_A1: return "rgb5_a1";
case GL_RGB565: return "rgb565";
case GL_STENCIL_INDEX8: return "stencil_index8";
default:
DE_ASSERT(DE_FALSE);
return "";
}
}
CreateImageGLES2 (EglTestContext& eglTestCtx, EGLint target, GLenum storage, bool useTexLevel0 = false)
: TestCase (eglTestCtx, (string("create_image_gles2_") + getTargetName(target) + "_" + getStorageName(storage) + (useTexLevel0 ? "_level0_only" : "")).c_str(), "Create EGLImage from GLES2 object")
, m_target (target)
, m_storage (storage)
, m_useTexLevel0 (useTexLevel0)
{
}
IterateResult iterate (void)
{
TestLog& log = m_testCtx.getLog();
ExtFuncTable efTable;
if (m_target == EGL_GL_TEXTURE_2D_KHR)
CHECK_EXTENSIONS({"EGL_KHR_gl_texture_2D_image"});
else if (m_target == EGL_GL_RENDERBUFFER_KHR)
CHECK_EXTENSIONS({"EGL_KHR_gl_renderbuffer_image"});
else
CHECK_EXTENSIONS({"EGL_KHR_gl_texture_cubemap_image"});
// Initialize result.
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
// Create GLES2 context
EGLint configId = GLES2Context::getConfigIdForApi(m_eglTestCtx.getConfigs(), EGL_OPENGL_ES2_BIT);
log << TestLog::Message << "Using EGL config " << configId << TestLog::EndMessage;
GLES2Context context(m_eglTestCtx, configId, 64, 64);
switch (m_target)
{
case EGL_GL_TEXTURE_2D_KHR:
{
deUint32 tex = 1;
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, tex));
// Specify mipmap level 0
GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_2D, 0, m_storage, 64, 64, 0, m_storage, GL_UNSIGNED_BYTE, DE_NULL));
if (!m_useTexLevel0)
{
// Set minification filter to linear. This makes the texture complete.
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
}
// Else spec allows using incomplete texture when miplevel 0 is only used and specified.
// Create EGL image
EGLint attribs[] = { EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE };
EGLImageKHR image = CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(deUintptr)tex, attribs), EGL_SUCCESS);
if (image == EGL_NO_IMAGE_KHR)
{
log << TestLog::Message << " Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
}
// Destroy image
CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
// Destroy texture object
GLU_CHECK_CALL(glDeleteTextures(1, &tex));
break;
}
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
{
deUint32 tex = 1;
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_CUBE_MAP, tex));
// Specify mipmap level 0 for all faces
GLenum faces[] =
{
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
for (int faceNdx = 0; faceNdx < DE_LENGTH_OF_ARRAY(faces); faceNdx++)
GLU_CHECK_CALL(glTexImage2D(faces[faceNdx], 0, m_storage, 64, 64, 0, m_storage, GL_UNSIGNED_BYTE, DE_NULL));
if (!m_useTexLevel0)
{
// Set minification filter to linear.
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
}
// Create EGL image
EGLint attribs[] = { EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE };
EGLImageKHR image = CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), m_target, (EGLClientBuffer)(deUintptr)tex, attribs), EGL_SUCCESS);
if (image == EGL_NO_IMAGE_KHR)
{
log << TestLog::Message << " Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
}
// Destroy image
CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
// Destroy texture object
GLU_CHECK_CALL(glDeleteTextures(1, &tex));
break;
}
case EGL_GL_RENDERBUFFER_KHR:
{
// Create renderbuffer.
deUint32 rbo = 1;
GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, rbo));
// Specify storage.
GLU_CHECK_CALL(glRenderbufferStorage(GL_RENDERBUFFER, m_storage, 64, 64));
// Create EGL image
EGLImageKHR image = CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), EGL_GL_RENDERBUFFER_KHR, (EGLClientBuffer)(deUintptr)rbo, DE_NULL), EGL_SUCCESS);
if (image == EGL_NO_IMAGE_KHR)
{
log << TestLog::Message << " Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
}
// Destroy image
CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
// Destroy texture object
GLU_CHECK_CALL(glDeleteRenderbuffers(1, &rbo));
break;
}
default:
DE_ASSERT(DE_FALSE);
break;
}
return STOP;
}
private:
EGLint m_target;
GLenum m_storage;
bool m_useTexLevel0;
};
class ImageTargetGLES2 : public TestCase
{
public:
static const char* getTargetName (GLenum target)
{
switch (target)
{
case GL_TEXTURE_2D: return "tex2d";
case GL_RENDERBUFFER: return "renderbuffer";
default:
DE_ASSERT(DE_FALSE);
return "";
}
}
ImageTargetGLES2 (EglTestContext& eglTestCtx, GLenum target)
: TestCase (eglTestCtx, (string("image_target_gles2_") + getTargetName(target)).c_str(), "Use EGLImage as GLES2 object")
, m_target (target)
{
}
IterateResult iterate (void)
{
TestLog& log = m_testCtx.getLog();
ExtFuncTable efTable;
// \todo [2011-07-21 pyry] Try all possible EGLImage sources
CHECK_EXTENSIONS({"EGL_KHR_gl_texture_2D_image"});
// Initialize result.
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
// Create GLES2 context
EGLint configId = GLES2Context::getConfigIdForApi(m_eglTestCtx.getConfigs(), EGL_OPENGL_ES2_BIT);
log << TestLog::Message << "Using EGL config " << configId << TestLog::EndMessage;
GLES2Context context(m_eglTestCtx, configId, 64, 64);
// Check for OES_EGL_image
{
const char* glExt = (const char*)glGetString(GL_EXTENSIONS);
if (string(glExt).find("GL_OES_EGL_image") == string::npos)
throw tcu::NotSupportedError("Extension not supported", "GL_OES_EGL_image", __FILE__, __LINE__);
TCU_CHECK(efTable.glEGLImageTargetTexture2DOES);
TCU_CHECK(efTable.glEGLImageTargetRenderbufferStorageOES);
}
// Create GL_TEXTURE_2D and EGLImage from it.
log << TestLog::Message << "Creating EGLImage using GL_TEXTURE_2D with GL_RGBA storage" << TestLog::EndMessage;
deUint32 srcTex = 1;
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, srcTex));
GLU_CHECK_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, DE_NULL));
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
// Create EGL image
EGLint attribs[] = { EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_NONE };
EGLImageKHR image = CHECK_EXT_CALL_ERR(eglCreateImageKHR(context.getEglDisplay(), context.getEglContext(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(deUintptr)srcTex, attribs), EGL_SUCCESS);
if (image == EGL_NO_IMAGE_KHR)
{
log << TestLog::Message << " Fail: Got EGL_NO_IMAGE_KHR!" << TestLog::EndMessage;
if (m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got EGL_NO_IMAGE_KHR");
}
// Create texture or renderbuffer
if (m_target == GL_TEXTURE_2D)
{
log << TestLog::Message << "Creating GL_TEXTURE_2D from EGLimage" << TestLog::EndMessage;
deUint32 dstTex = 2;
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, dstTex));
CHECK_GL_EXT_CALL(glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image), GL_NO_ERROR);
GLU_CHECK_CALL(glDeleteTextures(1, &dstTex));
}
else
{
DE_ASSERT(m_target == GL_RENDERBUFFER);
log << TestLog::Message << "Creating GL_RENDERBUFFER from EGLimage" << TestLog::EndMessage;
deUint32 dstRbo = 2;
GLU_CHECK_CALL(glBindRenderbuffer(GL_RENDERBUFFER, dstRbo));
CHECK_GL_EXT_CALL(glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)image), GL_NO_ERROR);
GLU_CHECK_CALL(glDeleteRenderbuffers(1, &dstRbo));
}
// Destroy image
CHECK_EXT_CALL_RET(eglDestroyImageKHR(context.getEglDisplay(), image), (EGLBoolean)EGL_TRUE, EGL_SUCCESS);
// Destroy source texture object
GLU_CHECK_CALL(glDeleteTextures(1, &srcTex));
return STOP;
}
private:
GLenum m_target;
};
class ApiTests : public TestCaseGroup
{
public:
ApiTests (EglTestContext& eglTestCtx)
: TestCaseGroup(eglTestCtx, "api", "EGLImage API tests")
{
}
void init (void)
{
addChild(new Image::InvalidCreateImage(m_eglTestCtx));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_2D_KHR, GL_RGB));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_2D_KHR, GL_RGBA));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_2D_KHR, GL_RGBA, true));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, GL_RGB));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, GL_RGBA));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR, GL_RGBA, true));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR, GL_RGBA));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR, GL_RGBA));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR, GL_RGBA));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR, GL_RGBA));
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR, GL_RGBA));
static const GLenum rboStorages[] =
{
GL_DEPTH_COMPONENT16,
GL_RGBA4,
GL_RGB5_A1,
GL_RGB565,
GL_STENCIL_INDEX8
};
for (int storageNdx = 0; storageNdx < DE_LENGTH_OF_ARRAY(rboStorages); storageNdx++)
addChild(new Image::CreateImageGLES2(m_eglTestCtx, EGL_GL_RENDERBUFFER_KHR, rboStorages[storageNdx]));
addChild(new Image::ImageTargetGLES2(m_eglTestCtx, GL_TEXTURE_2D));
addChild(new Image::ImageTargetGLES2(m_eglTestCtx, GL_RENDERBUFFER));
}
};
} // Image
ImageTests::ImageTests (EglTestContext& eglTestCtx)
: TestCaseGroup(eglTestCtx, "image", "EGLImage Tests")
{
}
ImageTests::~ImageTests (void)
{
}
void ImageTests::init (void)
{
addChild(new Image::ApiTests(m_eglTestCtx));
addChild(new Image::SimpleCreationTests(m_eglTestCtx));
addChild(new Image::ModifyTests(m_eglTestCtx));
addChild(new Image::MultiContextRenderTests(m_eglTestCtx));
}
} // egl
} // deqp