blob: 5267c60ebcc0c74318c2af5634c6bfde1fc7d3d7 [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 gles2 sharing tests
*//*--------------------------------------------------------------------*/
#include "teglGLES2SharingTests.hpp"
#include "teglGLES2SharingThreadedTests.hpp"
#include "egluNativeWindow.hpp"
#include "egluUtil.hpp"
#include "tcuCommandLine.hpp"
#include "tcuImageCompare.hpp"
#include "tcuSurface.hpp"
#include "tcuTestLog.hpp"
#include "tcuTexture.hpp"
#include "tcuTextureUtil.hpp"
#include "deUniquePtr.hpp"
#include "deRandom.hpp"
#include "deMath.h"
#include "deMemory.h"
#include "deString.h"
#include "gluDefs.hpp"
#include <GLES2/gl2.h>
#include <memory>
#include <sstream>
#include <vector>
using std::vector;
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 (const std::exception&)
{
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
class GLES2SharingTest : public TestCase
{
public:
enum ResourceType
{
BUFFER = 0,
TEXTURE,
RENDERBUFFER,
SHADER_PROGRAM
};
struct TestSpec
{
ResourceType type;
bool destroyContextBFirst;
bool useResource;
bool destroyOnContexB;
bool initializeData;
bool renderOnContexA;
bool renderOnContexB;
bool verifyOnContexA;
bool verifyOnContexB;
};
GLES2SharingTest (EglTestContext& eglTestCtx, const char* name , const char* desc, const TestSpec& spec);
IterateResult iterate (void);
private:
TestSpec m_spec;
EGLContext createContext (EGLDisplay display, EGLContext share, EGLConfig config);
void destroyContext (EGLDisplay display, EGLContext context);
void makeCurrent (EGLDisplay display, EGLContext context, EGLSurface surafec);
protected:
de::Random m_random;
tcu::TestLog& m_log;
virtual void createResource (void) { DE_ASSERT(false); }
virtual void destroyResource (void) { DE_ASSERT(false); }
virtual void renderResource (tcu::Surface* screen, tcu::Surface* reference) { DE_UNREF(screen); DE_UNREF(reference); DE_ASSERT(false); }
};
GLES2SharingTest::GLES2SharingTest (EglTestContext& eglTestCtx, const char* name , const char* desc, const TestSpec& spec)
: TestCase (eglTestCtx, name, desc)
, m_spec (spec)
, m_random (deStringHash(name))
, m_log (eglTestCtx.getTestContext().getLog())
{
}
EGLContext GLES2SharingTest::createContext (EGLDisplay display, EGLContext share, EGLConfig config)
{
EGLContext context = EGL_NO_CONTEXT;
EGLint attriblist[] =
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGLint configId = -1;
eglGetConfigAttrib(display, config, EGL_CONFIG_ID, &configId);
TCU_CHECK_EGL_CALL(eglBindAPI(EGL_OPENGL_ES_API));
context = eglCreateContext(display, config, share, attriblist);
TCU_CHECK_EGL_MSG("Failed to create GLES2 context");
TCU_CHECK(context != EGL_NO_CONTEXT);
return context;
}
void GLES2SharingTest::destroyContext (EGLDisplay display, EGLContext context)
{
TCU_CHECK_EGL_CALL(eglDestroyContext(display, context));
}
void GLES2SharingTest::makeCurrent (EGLDisplay display, EGLContext context, EGLSurface surface)
{
TCU_CHECK_EGL_CALL(eglMakeCurrent(display, surface, surface, context));
}
TestCase::IterateResult GLES2SharingTest::iterate (void)
{
tcu::TestLog& log = m_testCtx.getLog();
vector<EGLConfig> configs;
EGLint attribList[] =
{
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_ALPHA_SIZE, 1,
EGL_NONE
};
tcu::egl::Display& display = m_eglTestCtx.getDisplay();
display.chooseConfig(attribList, configs);
EGLConfig config = configs[0];
de::UniquePtr<eglu::NativeWindow> window (m_eglTestCtx.createNativeWindow(display.getEGLDisplay(), config, DE_NULL, 480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
tcu::egl::WindowSurface surface (display, eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, display.getEGLDisplay(), config, DE_NULL));
m_log << tcu::TestLog::Message << "Create context A" << tcu::TestLog::EndMessage;
EGLContext contextA = createContext(display.getEGLDisplay(), EGL_NO_CONTEXT, config);
m_log << tcu::TestLog::Message << "Create context B" << tcu::TestLog::EndMessage;
EGLContext contextB = createContext(display.getEGLDisplay(), contextA, config);
bool isOk = true;
if (m_spec.useResource)
{
m_log << tcu::TestLog::Message << "Make current context A" << tcu::TestLog::EndMessage;
makeCurrent(display.getEGLDisplay(), contextA, surface.getEGLSurface());
m_log << tcu::TestLog::Message << "Creating resource" << tcu::TestLog::EndMessage;
createResource();
int width = 240;
int height = 240;
if (m_spec.renderOnContexA)
{
m_log << tcu::TestLog::Message << "Render resource" << tcu::TestLog::EndMessage;
if (m_spec.verifyOnContexA)
{
tcu::Surface screen (width, height);
tcu::Surface ref (width, height);
renderResource(&screen, &ref);
if (!fuzzyCompare(log, "Rendered image", "Rendering result comparision", ref, screen, 0.05f, tcu::COMPARE_LOG_RESULT))
isOk = false;
}
else
{
renderResource(NULL, NULL);
}
}
if (m_spec.renderOnContexB)
{
m_log << tcu::TestLog::Message << "Make current context B" << tcu::TestLog::EndMessage;
makeCurrent(display.getEGLDisplay(), contextB, surface.getEGLSurface());
m_log << tcu::TestLog::Message << "Render resource" << tcu::TestLog::EndMessage;
if (m_spec.verifyOnContexB)
{
tcu::Surface screen (width, height);
tcu::Surface ref (width, height);
renderResource(&screen, &ref);
if (!fuzzyCompare(log, "Rendered image", "Rendering result comparision", ref, screen, 0.05f, tcu::COMPARE_LOG_RESULT))
isOk = false;
}
else
{
renderResource(NULL, NULL);
}
}
if (m_spec.destroyOnContexB)
{
m_log << tcu::TestLog::Message << "Make current context B" << tcu::TestLog::EndMessage;
makeCurrent(display.getEGLDisplay(), contextB, surface.getEGLSurface());
m_log << tcu::TestLog::Message << "Destroy resource" << tcu::TestLog::EndMessage;
destroyResource();
}
else
{
m_log << tcu::TestLog::Message << "Make current context A" << tcu::TestLog::EndMessage;
makeCurrent(display.getEGLDisplay(), contextA, surface.getEGLSurface());
m_log << tcu::TestLog::Message << "Destroy resource" << tcu::TestLog::EndMessage;
destroyResource();
}
}
if (m_spec.destroyContextBFirst)
{
m_log << tcu::TestLog::Message << "Destroy context B" << tcu::TestLog::EndMessage;
destroyContext(display.getEGLDisplay(), contextB);
m_log << tcu::TestLog::Message << "Destroy context A" << tcu::TestLog::EndMessage;
destroyContext(display.getEGLDisplay(), contextA);
}
else
{
m_log << tcu::TestLog::Message << "Destroy context A" << tcu::TestLog::EndMessage;
destroyContext(display.getEGLDisplay(), contextA);
m_log << tcu::TestLog::Message << "Destroy context B" << tcu::TestLog::EndMessage;
destroyContext(display.getEGLDisplay(), contextB);
}
if (isOk)
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
else
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
class GLES2BufferSharingTest : public GLES2SharingTest
{
public:
GLES2BufferSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, const GLES2SharingTest::TestSpec& spec);
private:
GLuint m_glBuffer;
std::vector<GLubyte> m_buffer;
virtual void createResource (void);
virtual void destroyResource (void);
virtual void renderResource (tcu::Surface* screen, tcu::Surface* reference);
};
GLES2BufferSharingTest::GLES2BufferSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, const GLES2SharingTest::TestSpec& spec)
: GLES2SharingTest (eglTestCtx, name, desc, spec)
, m_glBuffer (0)
{
}
void GLES2BufferSharingTest::createResource (void)
{
int size = 16*16*4;
m_buffer.reserve(size);
for (int i = 0; i < size; i++)
m_buffer.push_back((GLubyte)m_random.getInt(0, 255));
GLU_CHECK_CALL(glGenBuffers(1, &m_glBuffer));
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_glBuffer));
GLU_CHECK_CALL(glBufferData(GL_ARRAY_BUFFER, (GLsizei)(m_buffer.size() * sizeof(GLubyte)), &(m_buffer[0]), GL_DYNAMIC_DRAW));
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLES2BufferSharingTest::destroyResource (void)
{
GLU_CHECK_CALL(glDeleteBuffers(1, &m_glBuffer));
m_buffer.clear();
}
void GLES2BufferSharingTest::renderResource (tcu::Surface* screen, tcu::Surface* reference)
{
DE_ASSERT((screen && reference) || (!screen && !reference));
const char* vertexShader = ""
"attribute mediump vec2 a_pos;\n"
"attribute mediump float a_color;\n"
"varying mediump float v_color;\n"
"void main(void)\n"
"{\n"
"\tv_color = a_color;\n"
"\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
"}\n";
const char* fragmentShader = ""
"varying mediump float v_color;\n"
"void main(void)\n"
"{\n"
"\tgl_FragColor = vec4(v_color, v_color, v_color, 1.0);\n"
"}\n";
Program program(vertexShader, fragmentShader);
if (!program.isOk())
TCU_FAIL("Failed to compile shader program");
std::vector<deUint16> indices;
std::vector<float> coords;
DE_ASSERT(m_buffer.size() % 4 == 0);
for (int i = 0; i < (int)m_buffer.size() / 4; i++)
{
indices.push_back(i*4);
indices.push_back(i*4 + 1);
indices.push_back(i*4 + 2);
indices.push_back(i*4 + 2);
indices.push_back(i*4 + 3);
indices.push_back(i*4);
coords.push_back(0.125f * (i % 16) - 1.0f);
coords.push_back(0.125f * ((int)(i / 16.0f)) - 1.0f);
coords.push_back(0.125f * (i % 16) - 1.0f);
coords.push_back(0.125f * ((int)(i / 16.0f) + 1) - 1.0f);
coords.push_back(0.125f * ((i % 16) + 1) - 1.0f);
coords.push_back(0.125f * ((int)(i / 16.0f) + 1) - 1.0f);
coords.push_back(0.125f * ((i % 16) + 1) - 1.0f);
coords.push_back(0.125f * ((int)(i / 16.0f)) - 1.0f);
}
int width = 240;
int height = 240;
if (screen)
{
width = screen->getWidth();
height = screen->getHeight();
}
GLU_CHECK_CALL(glViewport(0, 0, width, height));
GLU_CHECK_CALL(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
GLU_CHECK_CALL(glUseProgram(program.getProgram()));
GLuint gridLocation = glGetAttribLocation(program.getProgram(), "a_pos");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(gridLocation != (GLuint)-1);
GLuint colorLocation = glGetAttribLocation(program.getProgram(), "a_color");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(colorLocation != (GLuint)-1);
GLU_CHECK_CALL(glEnableVertexAttribArray(colorLocation));
GLU_CHECK_CALL(glEnableVertexAttribArray(gridLocation));
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_glBuffer));
GLU_CHECK_CALL(glVertexAttribPointer(colorLocation, 1, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL));
GLU_CHECK_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
GLU_CHECK_CALL(glVertexAttribPointer(gridLocation, 2, GL_FLOAT, GL_FALSE, 0, &(coords[0])));
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, (GLsizei)indices.size(), GL_UNSIGNED_SHORT, &(indices[0])));
GLU_CHECK_CALL(glDisableVertexAttribArray(colorLocation));
GLU_CHECK_CALL(glDisableVertexAttribArray(gridLocation));
GLU_CHECK_CALL(glUseProgram(0));
if (screen)
{
tcu::clear(reference->getAccess(), tcu::IVec4(0xff, 0, 0, 0xff));
glReadPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
for (int i = 0; i < (int)m_buffer.size() / 4; i++)
{
float fx1 = 0.125f * (i % 16) - 1.0f;
float fy1 = 0.125f * ((int)(i / 16.0f)) - 1.0f;
float fx2 = 0.125f * ((i % 16) + 1) - 1.0f;
float fy2 = 0.125f * ((int)((i / 16.0f) + 1)) - 1.0f;
int ox = deRoundFloatToInt32(width / 2.0f);
int oy = deRoundFloatToInt32(height / 2.0f);
int x1 = deRoundFloatToInt32((width * fx1 / 2.0f) + ox);
int y1 = deRoundFloatToInt32((height * fy1 / 2.0f) + oy);
int x2 = deRoundFloatToInt32((width * fx2 / 2.0f) + ox);
int y2 = deRoundFloatToInt32((height * fy2 / 2.0f) + oy);
for (int x = x1; x < x2; x++)
{
for (int y = y1; y < y2; y++)
{
float xf = ((float)(x-x1) + 0.5f) / (float)(x2 - x1);
float yf = ((float)(y-y1) + 0.5f) / (float)(y2 - y1);
bool tri = yf >= xf;
deUint8 a = m_buffer[i*4 + (tri ? 1 : 3)];
deUint8 b = m_buffer[i*4 + (tri ? 2 : 0)];
deUint8 c = m_buffer[i*4 + (tri ? 0 : 2)];
float s = tri ? xf : 1.0f-xf;
float t = tri ? 1.0f-yf : yf;
float val = (float)a + (float)(b-a)*s + (float)(c-a)*t;
reference->setPixel(x, y, tcu::RGBA((deUint8)val, (deUint8)val, (deUint8)val, 255));
}
}
}
}
}
class GLES2TextureSharingTest : public GLES2SharingTest
{
public:
GLES2TextureSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, const GLES2SharingTest::TestSpec& spec);
private:
GLuint m_glTexture;
tcu::Texture2D m_texture;
virtual void createResource (void);
virtual void destroyResource (void);
virtual void renderResource (tcu::Surface* screen, tcu::Surface* reference);
};
GLES2TextureSharingTest::GLES2TextureSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, const GLES2SharingTest::TestSpec& spec)
: GLES2SharingTest (eglTestCtx, name, desc, spec)
, m_glTexture (0)
, m_texture (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1)
{
}
void GLES2TextureSharingTest::createResource (void)
{
int width = 128;
int height = 128;
m_texture = tcu::Texture2D(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), width, height);
m_texture.allocLevel(0);
tcu::fillWithComponentGradients(m_texture.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
GLU_CHECK_CALL(glGenTextures(1, &m_glTexture));
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, m_glTexture));
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
GLU_CHECK_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
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(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_texture.getLevel(0).getDataPtr()));
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, 0));
}
void GLES2TextureSharingTest::destroyResource (void)
{
GLU_CHECK_CALL(glDeleteTextures(1, &m_glTexture));
}
void GLES2TextureSharingTest::renderResource (tcu::Surface* screen, tcu::Surface* reference)
{
DE_ASSERT((screen && reference) || (!screen && !reference));
const char* vertexShader = ""
"attribute mediump vec2 a_pos;\n"
"attribute mediump vec2 a_texCorod;\n"
"varying mediump vec2 v_texCoord;\n"
"void main(void)\n"
"{\n"
"\tv_texCoord = a_texCorod;\n"
"\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
"}\n";
const char* fragmentShader = ""
"varying mediump vec2 v_texCoord;\n"
"uniform sampler2D u_sampler;\n"
"void main(void)\n"
"{\n"
"\tgl_FragColor = texture2D(u_sampler, v_texCoord);\n"
"}\n";
Program program(vertexShader, fragmentShader);
if (!program.isOk())
TCU_FAIL("Failed to compile shader program");
int width = 240;
int height = 240;
if (screen)
{
width = screen->getWidth();
height = screen->getHeight();
}
static const GLfloat coords[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
static const GLfloat texCoords[] = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
static const GLushort indices[] = {
0, 1, 2,
2, 3, 0
};
GLU_CHECK_CALL(glViewport(0, 0, width, height));
GLU_CHECK_CALL(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
GLU_CHECK_CALL(glUseProgram(program.getProgram()));
GLuint coordLocation = glGetAttribLocation(program.getProgram(), "a_pos");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(coordLocation != (GLuint)-1);
GLuint texCoordLocation = glGetAttribLocation(program.getProgram(), "a_texCorod");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(texCoordLocation != (GLuint)-1);
GLuint samplerLocation = glGetUniformLocation(program.getProgram(), "u_sampler");
GLU_CHECK_MSG("glGetUniformLocation()");
TCU_CHECK(samplerLocation != (GLuint)-1);
GLU_CHECK_CALL(glActiveTexture(GL_TEXTURE0));
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, m_glTexture));
GLU_CHECK_CALL(glUniform1i(samplerLocation, 0));
GLU_CHECK_CALL(glEnableVertexAttribArray(texCoordLocation));
GLU_CHECK_CALL(glEnableVertexAttribArray(coordLocation));
GLU_CHECK_CALL(glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texCoords));
GLU_CHECK_CALL(glVertexAttribPointer(coordLocation, 2, GL_FLOAT, GL_FALSE, 0, coords));
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices));
GLU_CHECK_CALL(glDisableVertexAttribArray(coordLocation));
GLU_CHECK_CALL(glDisableVertexAttribArray(texCoordLocation));
GLU_CHECK_CALL(glBindTexture(GL_TEXTURE_2D, 0));
GLU_CHECK_CALL(glUseProgram(0));
if (screen)
{
glReadPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
float t = ((float)x / (width - 1.0f));
float s = ((float)y / (height - 1.0f));
float lod = 0.0f;
tcu::Vec4 color = m_texture.sample(tcu::Sampler(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR), t, s, lod);
int r = deClamp32((int)(255.0f * color.x()), 0, 255);
int g = deClamp32((int)(255.0f * color.y()), 0, 255);
int b = deClamp32((int)(255.0f * color.z()), 0, 255);
int a = deClamp32((int)(255.0f * color.w()), 0, 255);
reference->setPixel(x, y, tcu::RGBA(r, g, b, a));
}
}
}
}
class GLES2ProgramSharingTest : public GLES2SharingTest
{
public:
GLES2ProgramSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, const GLES2SharingTest::TestSpec& spec);
private:
Program* m_program;
virtual void createResource (void);
virtual void destroyResource (void);
virtual void renderResource (tcu::Surface* screen, tcu::Surface* reference);
};
GLES2ProgramSharingTest::GLES2ProgramSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, const GLES2SharingTest::TestSpec& spec)
: GLES2SharingTest (eglTestCtx, name, desc, spec)
, m_program (NULL)
{
}
void GLES2ProgramSharingTest::createResource (void)
{
const char* vertexShader = ""
"attribute mediump vec2 a_pos;\n"
"attribute mediump vec4 a_color;\n"
"varying mediump vec4 v_color;\n"
"void main(void)\n"
"{\n"
"\tv_color = a_color;\n"
"\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
"}\n";
const char* fragmentShader = ""
"varying mediump vec4 v_color;\n"
"void main(void)\n"
"{\n"
"\tgl_FragColor = v_color;\n"
"}\n";
m_program = new Program(vertexShader, fragmentShader);
if (!m_program->isOk())
TCU_FAIL("Failed to compile shader program");
}
void GLES2ProgramSharingTest::destroyResource (void)
{
delete m_program;
}
void GLES2ProgramSharingTest::renderResource (tcu::Surface* screen, tcu::Surface* reference)
{
DE_ASSERT((screen && reference) || (!screen && !reference));
int width = 240;
int height = 240;
if (screen)
{
width = screen->getWidth();
height = screen->getHeight();
}
static const GLfloat coords[] = {
-0.9f, -0.9f,
0.9f, -0.9f,
0.9f, 0.9f,
-0.9f, 0.9f
};
static const GLfloat colors [] = {
0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
static const GLushort indices[] = {
0, 1, 2,
2, 3, 0
};
GLU_CHECK_CALL(glViewport(0, 0, width, height));
GLU_CHECK_CALL(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
GLU_CHECK_CALL(glUseProgram(m_program->getProgram()));
GLuint coordLocation = glGetAttribLocation(m_program->getProgram(), "a_pos");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(coordLocation != (GLuint)-1);
GLuint colorLocation = glGetAttribLocation(m_program->getProgram(), "a_color");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(colorLocation != (GLuint)-1);
GLU_CHECK_CALL(glEnableVertexAttribArray(colorLocation));
GLU_CHECK_CALL(glEnableVertexAttribArray(coordLocation));
GLU_CHECK_CALL(glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, colors));
GLU_CHECK_CALL(glVertexAttribPointer(coordLocation, 2, GL_FLOAT, GL_FALSE, 0, coords));
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices));
GLU_CHECK_CALL(glDisableVertexAttribArray(coordLocation));
GLU_CHECK_CALL(glDisableVertexAttribArray(colorLocation));
GLU_CHECK_CALL(glUseProgram(0));
if (screen)
{
glReadPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
tcu::clear(reference->getAccess(), tcu::IVec4(0xff, 0, 0, 0xff));
int x1 = (int)((width/2.0f) * (-0.9f) + (width/2.0f));
int x2 = (int)((width/2.0f) * 0.9f + (width/2.0f));
int y1 = (int)((height/2.0f) * (-0.9f) + (height/2.0f));
int y2 = (int)((height/2.0f) * 0.9f + (height/2.0f));
for (int x = x1; x <= x2; x++)
{
for (int y = y1; y <= y2; y++)
{
float t = ((float)(x-x1) / (x2 - x1));
float s = ((float)(y-y1) / (y2-y1));
bool isUpper = t > s;
tcu::Vec4 a(colors[0], colors[1], colors[2], colors[3]);
tcu::Vec4 b(colors[4 + 0], colors[4 + 1], colors[4 + 2], colors[4 + 3]);
tcu::Vec4 c(colors[8 + 0], colors[8 + 1], colors[8 + 2], colors[8 + 3]);
tcu::Vec4 d(colors[12 + 0], colors[12 + 1], colors[12 + 2], colors[12 + 3]);
tcu::Vec4 color;
if (isUpper)
color = a * (1.0f - t) + b * (t - s) + s * c;
else
color = a * (1.0f - s) + d * (s - t) + t * c;
int red = deClamp32((int)(255.0f * color.x()), 0, 255);
int green = deClamp32((int)(255.0f * color.y()), 0, 255);
int blue = deClamp32((int)(255.0f * color.z()), 0, 255);
int alpha = deClamp32((int)(255.0f * color.w()), 0, 255);
reference->setPixel(x, y, tcu::RGBA(red, green, blue, alpha));
}
}
}
}
class GLES2ShaderSharingTest : public GLES2SharingTest
{
public:
GLES2ShaderSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, GLenum shaderType, const GLES2SharingTest::TestSpec& spec);
private:
GLuint m_shader;
GLenum m_shaderType;
virtual void createResource (void);
virtual void destroyResource (void);
virtual void renderResource (tcu::Surface* screen, tcu::Surface* reference);
};
GLES2ShaderSharingTest::GLES2ShaderSharingTest (EglTestContext& eglTestCtx, const char* name, const char* desc, GLenum shaderType, const GLES2SharingTest::TestSpec& spec)
: GLES2SharingTest (eglTestCtx, name, desc, spec)
, m_shader (0)
, m_shaderType (shaderType)
{
}
void GLES2ShaderSharingTest::createResource (void)
{
const char* vertexShader = ""
"attribute mediump vec2 a_pos;\n"
"attribute mediump vec4 a_color;\n"
"varying mediump vec4 v_color;\n"
"void main(void)\n"
"{\n"
"\tv_color = a_color;\n"
"\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
"}\n";
const char* fragmentShader = ""
"varying mediump vec4 v_color;\n"
"void main(void)\n"
"{\n"
"\tgl_FragColor = v_color;\n"
"}\n";
m_shader = glCreateShader(m_shaderType);
GLU_CHECK_MSG("glCreateShader()");
switch (m_shaderType)
{
case GL_VERTEX_SHADER:
GLU_CHECK_CALL(glShaderSource(m_shader, 1, &vertexShader, NULL));
break;
case GL_FRAGMENT_SHADER:
GLU_CHECK_CALL(glShaderSource(m_shader, 1, &fragmentShader, NULL));
break;
default:
DE_ASSERT(false);
}
GLU_CHECK_CALL(glCompileShader(m_shader));
GLint status = 0;
GLU_CHECK_CALL(glGetShaderiv(m_shader, GL_COMPILE_STATUS, &status));
if (!status)
{
char buffer[256];
GLU_CHECK_CALL(glGetShaderInfoLog(m_shader, 256, NULL, buffer));
m_log << tcu::TestLog::Message << "Failed to compile shader" << tcu::TestLog::EndMessage;
switch (m_shaderType)
{
case GL_VERTEX_SHADER:
m_log << tcu::TestLog::Message << vertexShader << tcu::TestLog::EndMessage;
break;
case GL_FRAGMENT_SHADER:
m_log << tcu::TestLog::Message << fragmentShader << tcu::TestLog::EndMessage;
break;
default:
DE_ASSERT(false);
}
m_log << tcu::TestLog::Message << buffer << tcu::TestLog::EndMessage;
TCU_FAIL("Failed to compile shader");
}
}
void GLES2ShaderSharingTest::destroyResource (void)
{
GLU_CHECK_CALL(glDeleteShader(m_shader));
}
void GLES2ShaderSharingTest::renderResource (tcu::Surface* screen, tcu::Surface* reference)
{
DE_ASSERT((screen && reference) || (!screen && !reference));
int width = 240;
int height = 240;
const char* vertexShader = ""
"attribute mediump vec2 a_pos;\n"
"attribute mediump vec4 a_color;\n"
"varying mediump vec4 v_color;\n"
"void main(void)\n"
"{\n"
"\tv_color = a_color;\n"
"\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
"}\n";
const char* fragmentShader = ""
"varying mediump vec4 v_color;\n"
"void main(void)\n"
"{\n"
"\tgl_FragColor = v_color;\n"
"}\n";
GLuint otherShader = (GLuint)-1;
switch (m_shaderType)
{
case GL_VERTEX_SHADER:
otherShader = glCreateShader(GL_FRAGMENT_SHADER);
GLU_CHECK_MSG("glCreateShader()");
GLU_CHECK_CALL(glShaderSource(otherShader, 1, &fragmentShader, NULL));
break;
case GL_FRAGMENT_SHADER:
otherShader = glCreateShader(GL_VERTEX_SHADER);
GLU_CHECK_MSG("glCreateShader()");
GLU_CHECK_CALL(glShaderSource(otherShader, 1, &vertexShader, NULL));
break;
default:
DE_ASSERT(false);
}
GLU_CHECK_CALL(glCompileShader(otherShader));
GLint status = 0;
GLU_CHECK_CALL(glGetShaderiv(otherShader, GL_COMPILE_STATUS, &status));
if (!status)
{
char buffer[256];
GLU_CHECK_CALL(glGetShaderInfoLog(otherShader, 256, NULL, buffer));
m_log << tcu::TestLog::Message << "Failed to compile shader" << tcu::TestLog::EndMessage;
switch (m_shaderType)
{
case GL_FRAGMENT_SHADER:
m_log << tcu::TestLog::Message << vertexShader << tcu::TestLog::EndMessage;
break;
case GL_VERTEX_SHADER:
m_log << tcu::TestLog::Message << fragmentShader << tcu::TestLog::EndMessage;
break;
default:
DE_ASSERT(false);
}
m_log << tcu::TestLog::Message << buffer << tcu::TestLog::EndMessage;
TCU_FAIL("Failed to compile shader");
}
GLuint program = glCreateProgram();
GLU_CHECK_MSG("glCreateProgram()");
GLU_CHECK_CALL(glAttachShader(program, m_shader));
GLU_CHECK_CALL(glAttachShader(program, otherShader));
GLU_CHECK_CALL(glLinkProgram(program));
GLU_CHECK_CALL(glDeleteShader(otherShader));
status = 0;
GLU_CHECK_CALL(glGetProgramiv(program, GL_LINK_STATUS, &status));
if (!status)
{
char buffer[256];
GLU_CHECK_CALL(glGetProgramInfoLog(program, 256, NULL, buffer));
m_log << tcu::TestLog::Message << "Failed to link program" << tcu::TestLog::EndMessage;
m_log << tcu::TestLog::Message << vertexShader << tcu::TestLog::EndMessage;
m_log << tcu::TestLog::Message << fragmentShader << tcu::TestLog::EndMessage;
m_log << tcu::TestLog::Message << buffer << tcu::TestLog::EndMessage;
TCU_FAIL("Failed to link program");
}
if (screen)
{
width = screen->getWidth();
height = screen->getHeight();
}
static const GLfloat coords[] = {
-0.9f, -0.9f,
0.9f, -0.9f,
0.9f, 0.9f,
-0.9f, 0.9f
};
static const GLfloat colors [] = {
0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
static const GLushort indices[] = {
0, 1, 2,
2, 3, 0
};
GLU_CHECK_CALL(glViewport(0, 0, width, height));
GLU_CHECK_CALL(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
GLU_CHECK_CALL(glClear(GL_COLOR_BUFFER_BIT));
GLU_CHECK_CALL(glUseProgram(program));
GLuint coordLocation = glGetAttribLocation(program, "a_pos");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(coordLocation != (GLuint)-1);
GLuint colorLocation = glGetAttribLocation(program, "a_color");
GLU_CHECK_MSG("glGetAttribLocation()");
TCU_CHECK(colorLocation != (GLuint)-1);
GLU_CHECK_CALL(glEnableVertexAttribArray(colorLocation));
GLU_CHECK_CALL(glEnableVertexAttribArray(coordLocation));
GLU_CHECK_CALL(glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, colors));
GLU_CHECK_CALL(glVertexAttribPointer(coordLocation, 2, GL_FLOAT, GL_FALSE, 0, coords));
GLU_CHECK_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices));
GLU_CHECK_CALL(glDisableVertexAttribArray(coordLocation));
GLU_CHECK_CALL(glDisableVertexAttribArray(colorLocation));
GLU_CHECK_CALL(glUseProgram(0));
if (screen)
{
glReadPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
tcu::clear(reference->getAccess(), tcu::IVec4(0xff, 0, 0, 0xff));
int x1 = (int)((width/2.0f) * (-0.9f) + (width/2.0f));
int x2 = (int)((width/2.0f) * 0.9f + (width/2.0f));
int y1 = (int)((height/2.0f) * (-0.9f) + (height/2.0f));
int y2 = (int)((height/2.0f) * 0.9f + (height/2.0f));
for (int x = x1; x <= x2; x++)
{
for (int y = y1; y <= y2; y++)
{
float t = ((float)(x-x1) / (x2 - x1));
float s = ((float)(y-y1) / (y2-y1));
bool isUpper = t > s;
tcu::Vec4 a(colors[0], colors[1], colors[2], colors[3]);
tcu::Vec4 b(colors[4 + 0], colors[4 + 1], colors[4 + 2], colors[4 + 3]);
tcu::Vec4 c(colors[8 + 0], colors[8 + 1], colors[8 + 2], colors[8 + 3]);
tcu::Vec4 d(colors[12 + 0], colors[12 + 1], colors[12 + 2], colors[12 + 3]);
tcu::Vec4 color;
if (isUpper)
color = a * (1.0f - t) + b * (t - s) + s * c;
else
color = a * (1.0f - s) + d * (s - t) + t * c;
int red = deClamp32((int)(255.0f * color.x()), 0, 255);
int green = deClamp32((int)(255.0f * color.y()), 0, 255);
int blue = deClamp32((int)(255.0f * color.z()), 0, 255);
int alpha = deClamp32((int)(255.0f * color.w()), 0, 255);
reference->setPixel(x, y, tcu::RGBA(red, green, blue, alpha));
}
}
}
}
SharingTests::SharingTests (EglTestContext& eglTestCtx)
: TestCaseGroup (eglTestCtx, "sharing", "Sharing test cases")
{
}
void SharingTests::init (void)
{
TestCaseGroup* gles2 = new TestCaseGroup(m_eglTestCtx, "gles2", "OpenGL ES 2 sharing test");
TestCaseGroup* context = new TestCaseGroup(m_eglTestCtx, "context", "Context creation and destruction tests");
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = false;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = true;
spec.renderOnContexB = true;
spec.verifyOnContexA = true;
spec.verifyOnContexB = true;
context->addChild(new GLES2SharingTest(m_eglTestCtx, "create_destroy", "Simple context creation and destruction", spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = true;
spec.useResource = false;
spec.destroyOnContexB = false;
spec.initializeData = false;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
context->addChild(new GLES2SharingTest(m_eglTestCtx, "create_destroy_mixed", "Simple context creation and destruction test with different destruction order", spec));
}
gles2->addChild(context);
TestCaseGroup* buffer = new TestCaseGroup(m_eglTestCtx, "buffer", "Buffer creation, destruction and rendering test");
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
buffer->addChild(new GLES2BufferSharingTest(m_eglTestCtx, "create_delete", "Create and delete on shared context", spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = true;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
buffer->addChild(new GLES2BufferSharingTest(m_eglTestCtx, "create_delete_mixed", "Create and delet on different contexts", spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = true;
spec.renderOnContexB = true;
spec.verifyOnContexA = true;
spec.verifyOnContexB = true;
buffer->addChild(new GLES2BufferSharingTest(m_eglTestCtx, "render", "Create, rendering on two different contexts and delete", spec));
}
gles2->addChild(buffer);
TestCaseGroup* texture = new TestCaseGroup(m_eglTestCtx, "texture", "Texture creation, destruction and rendering tests");
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
texture->addChild(new GLES2TextureSharingTest(m_eglTestCtx, "create_delete", "Create and delete on shared context", spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = true;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
texture->addChild(new GLES2TextureSharingTest(m_eglTestCtx, "create_delete_mixed", "Create and delete on different contexts", spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = true;
spec.renderOnContexB = true;
spec.verifyOnContexA = true;
spec.verifyOnContexB = true;
texture->addChild(new GLES2TextureSharingTest(m_eglTestCtx, "render", "Create, render in two contexts and delete", spec));
}
gles2->addChild(texture);
TestCaseGroup* program = new TestCaseGroup(m_eglTestCtx, "program", "Program creation, destruction and rendering test");
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
program->addChild(new GLES2ProgramSharingTest(m_eglTestCtx, "create_delete", "Create and delete on shared context", spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = true;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
program->addChild(new GLES2ProgramSharingTest(m_eglTestCtx, "create_delete_mixed", "Create and delete on different contexts", spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = true;
spec.renderOnContexB = true;
spec.verifyOnContexA = true;
spec.verifyOnContexB = true;
program->addChild(new GLES2ProgramSharingTest(m_eglTestCtx, "render", "Create, render in two contexts and delete", spec));
}
gles2->addChild(program);
TestCaseGroup* shader = new TestCaseGroup(m_eglTestCtx, "shader", "Shader creation, destruction and rendering test");
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
shader->addChild(new GLES2ShaderSharingTest(m_eglTestCtx, "create_delete_vert", "Create and delete on shared context", GL_VERTEX_SHADER, spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = true;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
shader->addChild(new GLES2ShaderSharingTest(m_eglTestCtx, "create_delete_mixed_vert", "Create and delete on different contexts", GL_VERTEX_SHADER, spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = true;
spec.renderOnContexB = true;
spec.verifyOnContexA = true;
spec.verifyOnContexB = true;
shader->addChild(new GLES2ShaderSharingTest(m_eglTestCtx, "render_vert", "Create, render on two contexts and delete", GL_VERTEX_SHADER, spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
shader->addChild(new GLES2ShaderSharingTest(m_eglTestCtx, "create_delete_frag", "Create and delete on shared context", GL_FRAGMENT_SHADER, spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = true;
spec.initializeData = true;
spec.renderOnContexA = false;
spec.renderOnContexB = false;
spec.verifyOnContexA = false;
spec.verifyOnContexB = false;
shader->addChild(new GLES2ShaderSharingTest(m_eglTestCtx, "create_delete_mixed_frag", "Create and delete on different contexts", GL_FRAGMENT_SHADER, spec));
}
{
GLES2SharingTest::TestSpec spec;
spec.destroyContextBFirst = false;
spec.useResource = true;
spec.destroyOnContexB = false;
spec.initializeData = true;
spec.renderOnContexA = true;
spec.renderOnContexB = true;
spec.verifyOnContexA = true;
spec.verifyOnContexB = true;
shader->addChild(new GLES2ShaderSharingTest(m_eglTestCtx, "render_frag", "Create, render on two contexts and delete", GL_FRAGMENT_SHADER, spec));
}
gles2->addChild(shader);
gles2->addChild(new GLES2SharingThreadedTests(m_eglTestCtx));
addChild(gles2);
}
} // egl
} // deqp