blob: d60e18809713e7cab6e39b1b505af710f7ee5efd [file] [log] [blame] [edit]
/*-------------------------------------------------------------------------
* 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 Multi threaded EGL tests
*//*--------------------------------------------------------------------*/
#include "teglMultiThreadTests.hpp"
#include "egluNativeWindow.hpp"
#include "egluNativePixmap.hpp"
#include "egluUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuCommandLine.hpp"
#include "deRandom.hpp"
#include "deThread.hpp"
#include "deMutex.hpp"
#include "deSemaphore.hpp"
#include "deAtomic.h"
#include "deClock.h"
#include "eglwLibrary.hpp"
#include "eglwEnums.hpp"
#include <vector>
#include <set>
#include <string>
#include <sstream>
using std::ostringstream;
using std::pair;
using std::set;
using std::string;
using std::vector;
using namespace eglw;
namespace deqp
{
namespace egl
{
class ThreadLog
{
public:
class BeginMessageToken
{
};
class EndMessageToken
{
};
struct Message
{
Message(uint64_t timeUs_, const char *msg_) : timeUs(timeUs_), msg(msg_)
{
}
uint64_t timeUs;
string msg;
};
ThreadLog(void)
{
m_messages.reserve(100);
}
ThreadLog &operator<<(const BeginMessageToken &)
{
return *this;
}
ThreadLog &operator<<(const EndMessageToken &);
template <class T>
ThreadLog &operator<<(const T &t)
{
m_message << t;
return *this;
}
const vector<Message> &getMessages(void) const
{
return m_messages;
}
static BeginMessageToken BeginMessage;
static EndMessageToken EndMessage;
private:
ostringstream m_message;
vector<Message> m_messages;
};
ThreadLog &ThreadLog::operator<<(const EndMessageToken &)
{
m_messages.push_back(Message(deGetMicroseconds(), m_message.str().c_str()));
m_message.str("");
return *this;
}
ThreadLog::BeginMessageToken ThreadLog::BeginMessage;
ThreadLog::EndMessageToken ThreadLog::EndMessage;
class MultiThreadedTest;
class TestThread : public de::Thread
{
public:
enum ThreadStatus
{
THREADSTATUS_NOT_STARTED = 0,
THREADSTATUS_RUNNING,
THREADSTATUS_READY,
};
TestThread(MultiThreadedTest &test, int id);
void run(void);
ThreadStatus getStatus(void) const
{
return m_status;
}
ThreadLog &getLog(void)
{
return m_log;
}
int getId(void) const
{
return m_id;
}
void setStatus(ThreadStatus status)
{
m_status = status;
}
const Library &getLibrary(void) const;
// Test has stopped
class TestStop
{
};
private:
MultiThreadedTest &m_test;
const int m_id;
ThreadStatus m_status;
ThreadLog m_log;
};
class MultiThreadedTest : public TestCase
{
public:
MultiThreadedTest(EglTestContext &eglTestCtx, const char *name, const char *description, int threadCount,
uint64_t timeoutUs);
virtual ~MultiThreadedTest(void);
void init(void);
void deinit(void);
virtual bool runThread(TestThread &thread) = 0;
virtual IterateResult iterate(void);
void execTest(TestThread &thread);
const Library &getLibrary(void) const
{
return m_eglTestCtx.getLibrary();
}
protected:
void barrier(void);
private:
int m_threadCount;
bool m_initialized;
uint64_t m_startTimeUs;
const uint64_t m_timeoutUs;
bool m_ok;
bool m_supported;
vector<TestThread *> m_threads;
volatile int32_t m_barrierWaiters;
de::Semaphore m_barrierSemaphore1;
de::Semaphore m_barrierSemaphore2;
protected:
EGLDisplay m_display;
};
inline const Library &TestThread::getLibrary(void) const
{
return m_test.getLibrary();
}
TestThread::TestThread(MultiThreadedTest &test, int id) : m_test(test), m_id(id), m_status(THREADSTATUS_NOT_STARTED)
{
}
void TestThread::run(void)
{
m_status = THREADSTATUS_RUNNING;
try
{
m_test.execTest(*this);
}
catch (const TestThread::TestStop &)
{
getLog() << ThreadLog::BeginMessage << "Thread stopped" << ThreadLog::EndMessage;
}
catch (const tcu::NotSupportedError &e)
{
getLog() << ThreadLog::BeginMessage << "Not supported: '" << e.what() << "'" << ThreadLog::EndMessage;
}
catch (const std::exception &e)
{
getLog() << ThreadLog::BeginMessage << "Got exception: '" << e.what() << "'" << ThreadLog::EndMessage;
}
catch (...)
{
getLog() << ThreadLog::BeginMessage << "Unknown exception" << ThreadLog::EndMessage;
}
getLibrary().releaseThread();
m_status = THREADSTATUS_READY;
}
void MultiThreadedTest::execTest(TestThread &thread)
{
try
{
if (!runThread(thread))
m_ok = false;
}
catch (const TestThread::TestStop &)
{
// Thread exited due to error in other thread
throw;
}
catch (const tcu::NotSupportedError &)
{
m_supported = false;
// Release barriers
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
{
m_barrierSemaphore1.increment();
m_barrierSemaphore2.increment();
}
throw;
}
catch (...)
{
m_ok = false;
// Release barriers
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
{
m_barrierSemaphore1.increment();
m_barrierSemaphore2.increment();
}
throw;
}
}
MultiThreadedTest::MultiThreadedTest(EglTestContext &eglTestCtx, const char *name, const char *description,
int threadCount, uint64_t timeoutUs)
: TestCase(eglTestCtx, name, description)
, m_threadCount(threadCount)
, m_initialized(false)
, m_startTimeUs(0)
, m_timeoutUs(timeoutUs)
, m_ok(true)
, m_supported(true)
, m_barrierWaiters(0)
, m_barrierSemaphore1(0, 0)
, m_barrierSemaphore2(1, 0)
, m_display(EGL_NO_DISPLAY)
{
}
MultiThreadedTest::~MultiThreadedTest(void)
{
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
delete m_threads[threadNdx];
m_threads.clear();
}
void MultiThreadedTest::init(void)
{
m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
}
void MultiThreadedTest::deinit(void)
{
if (m_display != EGL_NO_DISPLAY)
{
m_eglTestCtx.getLibrary().terminate(m_display);
m_display = EGL_NO_DISPLAY;
}
}
void MultiThreadedTest::barrier(void)
{
{
const int32_t waiters = deAtomicIncrement32(&m_barrierWaiters);
if (waiters == m_threadCount)
{
m_barrierSemaphore2.decrement();
m_barrierSemaphore1.increment();
}
else
{
m_barrierSemaphore1.decrement();
m_barrierSemaphore1.increment();
}
}
{
const int32_t waiters = deAtomicDecrement32(&m_barrierWaiters);
if (waiters == 0)
{
m_barrierSemaphore1.decrement();
m_barrierSemaphore2.increment();
}
else
{
m_barrierSemaphore2.decrement();
m_barrierSemaphore2.increment();
}
}
// Barrier was released due an error in other thread
if (!m_ok || !m_supported)
throw TestThread::TestStop();
}
TestCase::IterateResult MultiThreadedTest::iterate(void)
{
if (!m_initialized)
{
m_testCtx.getLog() << tcu::TestLog::Message << "Thread timeout limit: " << m_timeoutUs << "us"
<< tcu::TestLog::EndMessage;
m_ok = true;
m_supported = true;
// Create threads
m_threads.reserve(m_threadCount);
for (int threadNdx = 0; threadNdx < m_threadCount; threadNdx++)
m_threads.push_back(new TestThread(*this, threadNdx));
m_startTimeUs = deGetMicroseconds();
// Run threads
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
m_threads[threadNdx]->start();
m_initialized = true;
}
int readyCount = 0;
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
{
if (m_threads[threadNdx]->getStatus() != TestThread::THREADSTATUS_RUNNING)
readyCount++;
}
if (readyCount == m_threadCount)
{
// Join threads
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
m_threads[threadNdx]->join();
// Get logs
{
vector<int> messageNdx;
messageNdx.resize(m_threads.size(), 0);
while (true)
{
int nextThreadNdx = -1;
uint64_t nextThreadTimeUs = 0;
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
{
if (messageNdx[threadNdx] >= (int)m_threads[threadNdx]->getLog().getMessages().size())
continue;
if (nextThreadNdx == -1 ||
nextThreadTimeUs > m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs)
{
nextThreadNdx = threadNdx;
nextThreadTimeUs = m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs;
}
}
if (nextThreadNdx == -1)
break;
m_testCtx.getLog() << tcu::TestLog::Message << "[" << (nextThreadTimeUs - m_startTimeUs) << "] ("
<< nextThreadNdx << ") "
<< m_threads[nextThreadNdx]->getLog().getMessages()[messageNdx[nextThreadNdx]].msg
<< tcu::TestLog::EndMessage;
messageNdx[nextThreadNdx]++;
}
}
// Destroy threads
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
delete m_threads[threadNdx];
m_threads.clear();
// Set result
if (m_ok)
{
if (!m_supported)
m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not Supported");
else
m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
}
else
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
else
{
// Check for timeout
const uint64_t currentTimeUs = deGetMicroseconds();
if (currentTimeUs - m_startTimeUs > m_timeoutUs)
{
// Get logs
{
vector<int> messageNdx;
messageNdx.resize(m_threads.size(), 0);
while (true)
{
int nextThreadNdx = -1;
uint64_t nextThreadTimeUs = 0;
for (int threadNdx = 0; threadNdx < (int)m_threads.size(); threadNdx++)
{
if (messageNdx[threadNdx] >= (int)m_threads[threadNdx]->getLog().getMessages().size())
continue;
if (nextThreadNdx == -1 ||
nextThreadTimeUs >
m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs)
{
nextThreadNdx = threadNdx;
nextThreadTimeUs =
m_threads[threadNdx]->getLog().getMessages()[messageNdx[threadNdx]].timeUs;
}
}
if (nextThreadNdx == -1)
break;
m_testCtx.getLog() << tcu::TestLog::Message << "[" << (nextThreadTimeUs - m_startTimeUs) << "] ("
<< nextThreadNdx << ") "
<< m_threads[nextThreadNdx]
->getLog()
.getMessages()[messageNdx[nextThreadNdx]]
.msg
<< tcu::TestLog::EndMessage;
messageNdx[nextThreadNdx]++;
}
}
m_testCtx.getLog() << tcu::TestLog::Message << "[" << (currentTimeUs - m_startTimeUs)
<< "] (-) Timeout, Limit: " << m_timeoutUs << "us" << tcu::TestLog::EndMessage;
m_testCtx.getLog() << tcu::TestLog::Message << "[" << (currentTimeUs - m_startTimeUs)
<< "] (-) Trying to perform resource cleanup..." << tcu::TestLog::EndMessage;
m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
return STOP;
}
// Sleep
deSleep(10);
}
return CONTINUE;
}
namespace
{
const char *configAttributeToString(EGLint e)
{
switch (e)
{
case EGL_BUFFER_SIZE:
return "EGL_BUFFER_SIZE";
case EGL_RED_SIZE:
return "EGL_RED_SIZE";
case EGL_GREEN_SIZE:
return "EGL_GREEN_SIZE";
case EGL_BLUE_SIZE:
return "EGL_BLUE_SIZE";
case EGL_LUMINANCE_SIZE:
return "EGL_LUMINANCE_SIZE";
case EGL_ALPHA_SIZE:
return "EGL_ALPHA_SIZE";
case EGL_ALPHA_MASK_SIZE:
return "EGL_ALPHA_MASK_SIZE";
case EGL_BIND_TO_TEXTURE_RGB:
return "EGL_BIND_TO_TEXTURE_RGB";
case EGL_BIND_TO_TEXTURE_RGBA:
return "EGL_BIND_TO_TEXTURE_RGBA";
case EGL_COLOR_BUFFER_TYPE:
return "EGL_COLOR_BUFFER_TYPE";
case EGL_CONFIG_CAVEAT:
return "EGL_CONFIG_CAVEAT";
case EGL_CONFIG_ID:
return "EGL_CONFIG_ID";
case EGL_CONFORMANT:
return "EGL_CONFORMANT";
case EGL_DEPTH_SIZE:
return "EGL_DEPTH_SIZE";
case EGL_LEVEL:
return "EGL_LEVEL";
case EGL_MAX_PBUFFER_WIDTH:
return "EGL_MAX_PBUFFER_WIDTH";
case EGL_MAX_PBUFFER_HEIGHT:
return "EGL_MAX_PBUFFER_HEIGHT";
case EGL_MAX_PBUFFER_PIXELS:
return "EGL_MAX_PBUFFER_PIXELS";
case EGL_MAX_SWAP_INTERVAL:
return "EGL_MAX_SWAP_INTERVAL";
case EGL_MIN_SWAP_INTERVAL:
return "EGL_MIN_SWAP_INTERVAL";
case EGL_NATIVE_RENDERABLE:
return "EGL_NATIVE_RENDERABLE";
case EGL_NATIVE_VISUAL_ID:
return "EGL_NATIVE_VISUAL_ID";
case EGL_NATIVE_VISUAL_TYPE:
return "EGL_NATIVE_VISUAL_TYPE";
case EGL_RENDERABLE_TYPE:
return "EGL_RENDERABLE_TYPE";
case EGL_SAMPLE_BUFFERS:
return "EGL_SAMPLE_BUFFERS";
case EGL_SAMPLES:
return "EGL_SAMPLES";
case EGL_STENCIL_SIZE:
return "EGL_STENCIL_SIZE";
case EGL_SURFACE_TYPE:
return "EGL_SURFACE_TYPE";
case EGL_TRANSPARENT_TYPE:
return "EGL_TRANSPARENT_TYPE";
case EGL_TRANSPARENT_RED_VALUE:
return "EGL_TRANSPARENT_RED_VALUE";
case EGL_TRANSPARENT_GREEN_VALUE:
return "EGL_TRANSPARENT_GREEN_VALUE";
case EGL_TRANSPARENT_BLUE_VALUE:
return "EGL_TRANSPARENT_BLUE_VALUE";
default:
return "<Unknown>";
}
}
} // namespace
class MultiThreadedConfigTest : public MultiThreadedTest
{
public:
MultiThreadedConfigTest(EglTestContext &context, const char *name, const char *description, int getConfigs,
int chooseConfigs, int query);
bool runThread(TestThread &thread);
private:
const int m_getConfigs;
const int m_chooseConfigs;
const int m_query;
};
MultiThreadedConfigTest::MultiThreadedConfigTest(EglTestContext &context, const char *name, const char *description,
int getConfigs, int chooseConfigs, int query)
: MultiThreadedTest(context, name, description, 2,
20000000 /*us = 20s*/) // \todo [mika] Set timeout to something relevant to frameworks timeout?
, m_getConfigs(getConfigs)
, m_chooseConfigs(chooseConfigs)
, m_query(query)
{
}
bool MultiThreadedConfigTest::runThread(TestThread &thread)
{
const Library &egl = getLibrary();
de::Random rnd(deInt32Hash(thread.getId() + 10435));
vector<EGLConfig> configs;
barrier();
for (int getConfigsNdx = 0; getConfigsNdx < m_getConfigs; getConfigsNdx++)
{
EGLint configCount;
// Get number of configs
{
EGLBoolean result;
result = egl.getConfigs(m_display, NULL, 0, &configCount);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglGetConfigs(" << m_display << ", NULL, 0, "
<< configCount << ")" << ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglGetConfigs()");
if (!result)
return false;
}
configs.resize(configs.size() + configCount);
// Get configs
if (configCount != 0)
{
EGLBoolean result;
result = egl.getConfigs(m_display, &(configs[configs.size() - configCount]), configCount, &configCount);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglGetConfigs(" << m_display << ", &configs' "
<< configCount << ", " << configCount << ")" << ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglGetConfigs()");
if (!result)
return false;
}
// Pop configs to stop config list growing
if (configs.size() > 40)
{
configs.erase(configs.begin() + 40, configs.end());
}
else
{
const int popCount = rnd.getInt(0, (int)(configs.size() - 2));
configs.erase(configs.begin() + (configs.size() - popCount), configs.end());
}
}
for (int chooseConfigsNdx = 0; chooseConfigsNdx < m_chooseConfigs; chooseConfigsNdx++)
{
EGLint configCount;
static const EGLint attribList[] = {EGL_NONE};
// Get number of configs
{
EGLBoolean result;
result = egl.chooseConfig(m_display, attribList, NULL, 0, &configCount);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglChooseConfig(" << m_display
<< ", { EGL_NONE }, NULL, 0, " << configCount << ")" << ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglChooseConfig()");
if (!result)
return false;
}
configs.resize(configs.size() + configCount);
// Get configs
if (configCount != 0)
{
EGLBoolean result;
result = egl.chooseConfig(m_display, attribList, &(configs[configs.size() - configCount]), configCount,
&configCount);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglChooseConfig(" << m_display
<< ", { EGL_NONE }, &configs, " << configCount << ", " << configCount << ")"
<< ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglChooseConfig()");
if (!result)
return false;
}
// Pop configs to stop config list growing
if (configs.size() > 40)
{
configs.erase(configs.begin() + 40, configs.end());
}
else
{
const int popCount = rnd.getInt(0, (int)(configs.size() - 2));
configs.erase(configs.begin() + (configs.size() - popCount), configs.end());
}
}
{
// Perform queries on configs
static const EGLint attributes[] = {EGL_BUFFER_SIZE,
EGL_RED_SIZE,
EGL_GREEN_SIZE,
EGL_BLUE_SIZE,
EGL_LUMINANCE_SIZE,
EGL_ALPHA_SIZE,
EGL_ALPHA_MASK_SIZE,
EGL_BIND_TO_TEXTURE_RGB,
EGL_BIND_TO_TEXTURE_RGBA,
EGL_COLOR_BUFFER_TYPE,
EGL_CONFIG_CAVEAT,
EGL_CONFIG_ID,
EGL_CONFORMANT,
EGL_DEPTH_SIZE,
EGL_LEVEL,
EGL_MAX_PBUFFER_WIDTH,
EGL_MAX_PBUFFER_HEIGHT,
EGL_MAX_PBUFFER_PIXELS,
EGL_MAX_SWAP_INTERVAL,
EGL_MIN_SWAP_INTERVAL,
EGL_NATIVE_RENDERABLE,
EGL_NATIVE_VISUAL_ID,
EGL_NATIVE_VISUAL_TYPE,
EGL_RENDERABLE_TYPE,
EGL_SAMPLE_BUFFERS,
EGL_SAMPLES,
EGL_STENCIL_SIZE,
EGL_SURFACE_TYPE,
EGL_TRANSPARENT_TYPE,
EGL_TRANSPARENT_RED_VALUE,
EGL_TRANSPARENT_GREEN_VALUE,
EGL_TRANSPARENT_BLUE_VALUE};
for (int queryNdx = 0; queryNdx < m_query; queryNdx++)
{
const EGLint attribute = attributes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(attributes) - 1)];
EGLConfig config = configs[rnd.getInt(0, (int)(configs.size() - 1))];
EGLint value;
EGLBoolean result;
result = egl.getConfigAttrib(m_display, config, attribute, &value);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglGetConfigAttrib(" << m_display << ", "
<< config << ", " << configAttributeToString(attribute) << ", " << value << ")"
<< ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()");
if (!result)
return false;
}
}
return true;
}
class MultiThreadedObjectTest : public MultiThreadedTest
{
public:
enum Type
{
TYPE_PBUFFER = (1 << 0),
TYPE_PIXMAP = (1 << 1),
TYPE_WINDOW = (1 << 2),
TYPE_SINGLE_WINDOW = (1 << 3),
TYPE_CONTEXT = (1 << 4)
};
MultiThreadedObjectTest(EglTestContext &context, const char *name, const char *description, uint32_t types);
~MultiThreadedObjectTest(void);
virtual void deinit(void);
bool runThread(TestThread &thread);
void createDestroyObjects(TestThread &thread, int count);
void pushObjectsToShared(TestThread &thread);
void pullObjectsFromShared(TestThread &thread, int pbufferCount, int pixmapCount, int windowCount,
int contextCount);
void querySetSharedObjects(TestThread &thread, int count);
void destroyObjects(TestThread &thread);
private:
EGLConfig m_config;
de::Random m_rnd0;
de::Random m_rnd1;
Type m_types;
volatile uint32_t m_hasWindow;
vector<pair<eglu::NativePixmap *, EGLSurface>> m_sharedNativePixmaps;
vector<pair<eglu::NativePixmap *, EGLSurface>> m_nativePixmaps0;
vector<pair<eglu::NativePixmap *, EGLSurface>> m_nativePixmaps1;
vector<pair<eglu::NativeWindow *, EGLSurface>> m_sharedNativeWindows;
vector<pair<eglu::NativeWindow *, EGLSurface>> m_nativeWindows0;
vector<pair<eglu::NativeWindow *, EGLSurface>> m_nativeWindows1;
vector<EGLSurface> m_sharedPbuffers;
vector<EGLSurface> m_pbuffers0;
vector<EGLSurface> m_pbuffers1;
vector<EGLContext> m_sharedContexts;
vector<EGLContext> m_contexts0;
vector<EGLContext> m_contexts1;
};
MultiThreadedObjectTest::MultiThreadedObjectTest(EglTestContext &context, const char *name, const char *description,
uint32_t type)
: MultiThreadedTest(context, name, description, 2,
20000000 /*us = 20s*/) // \todo [mika] Set timeout to something relevant to frameworks timeout?
, m_config(DE_NULL)
, m_rnd0(58204327)
, m_rnd1(230983)
, m_types((Type)type)
, m_hasWindow(0)
{
}
MultiThreadedObjectTest::~MultiThreadedObjectTest(void)
{
deinit();
}
void MultiThreadedObjectTest::deinit(void)
{
const Library &egl = getLibrary();
// Clear pbuffers
for (int pbufferNdx = 0; pbufferNdx < (int)m_pbuffers0.size(); pbufferNdx++)
{
if (m_pbuffers0[pbufferNdx] != EGL_NO_SURFACE)
{
egl.destroySurface(m_display, m_pbuffers0[pbufferNdx]);
EGLU_CHECK_MSG(egl, "eglDestroySurface()");
m_pbuffers0[pbufferNdx] = EGL_NO_SURFACE;
}
}
m_pbuffers0.clear();
for (int pbufferNdx = 0; pbufferNdx < (int)m_pbuffers1.size(); pbufferNdx++)
{
if (m_pbuffers1[pbufferNdx] != EGL_NO_SURFACE)
{
egl.destroySurface(m_display, m_pbuffers1[pbufferNdx]);
EGLU_CHECK_MSG(egl, "eglDestroySurface()");
m_pbuffers1[pbufferNdx] = EGL_NO_SURFACE;
}
}
m_pbuffers1.clear();
for (int pbufferNdx = 0; pbufferNdx < (int)m_sharedPbuffers.size(); pbufferNdx++)
{
if (m_sharedPbuffers[pbufferNdx] != EGL_NO_SURFACE)
{
egl.destroySurface(m_display, m_sharedPbuffers[pbufferNdx]);
EGLU_CHECK_MSG(egl, "eglDestroySurface()");
m_sharedPbuffers[pbufferNdx] = EGL_NO_SURFACE;
}
}
m_sharedPbuffers.clear();
for (int contextNdx = 0; contextNdx < (int)m_sharedContexts.size(); contextNdx++)
{
if (m_sharedContexts[contextNdx] != EGL_NO_CONTEXT)
{
egl.destroyContext(m_display, m_sharedContexts[contextNdx]);
EGLU_CHECK_MSG(egl, "eglDestroyContext()");
m_sharedContexts[contextNdx] = EGL_NO_CONTEXT;
}
}
m_sharedContexts.clear();
for (int contextNdx = 0; contextNdx < (int)m_contexts0.size(); contextNdx++)
{
if (m_contexts0[contextNdx] != EGL_NO_CONTEXT)
{
egl.destroyContext(m_display, m_contexts0[contextNdx]);
EGLU_CHECK_MSG(egl, "eglDestroyContext()");
m_contexts0[contextNdx] = EGL_NO_CONTEXT;
}
}
m_contexts0.clear();
for (int contextNdx = 0; contextNdx < (int)m_contexts1.size(); contextNdx++)
{
if (m_contexts1[contextNdx] != EGL_NO_CONTEXT)
{
egl.destroyContext(m_display, m_contexts1[contextNdx]);
EGLU_CHECK_MSG(egl, "eglDestroyContext()");
m_contexts1[contextNdx] = EGL_NO_CONTEXT;
}
}
m_contexts1.clear();
// Clear pixmaps
for (int pixmapNdx = 0; pixmapNdx < (int)m_nativePixmaps0.size(); pixmapNdx++)
{
if (m_nativePixmaps0[pixmapNdx].second != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, m_nativePixmaps0[pixmapNdx].second));
m_nativePixmaps0[pixmapNdx].second = EGL_NO_SURFACE;
delete m_nativePixmaps0[pixmapNdx].first;
m_nativePixmaps0[pixmapNdx].first = NULL;
}
m_nativePixmaps0.clear();
for (int pixmapNdx = 0; pixmapNdx < (int)m_nativePixmaps1.size(); pixmapNdx++)
{
if (m_nativePixmaps1[pixmapNdx].second != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, m_nativePixmaps1[pixmapNdx].second));
m_nativePixmaps1[pixmapNdx].second = EGL_NO_SURFACE;
delete m_nativePixmaps1[pixmapNdx].first;
m_nativePixmaps1[pixmapNdx].first = NULL;
}
m_nativePixmaps1.clear();
for (int pixmapNdx = 0; pixmapNdx < (int)m_sharedNativePixmaps.size(); pixmapNdx++)
{
if (m_sharedNativePixmaps[pixmapNdx].second != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, m_sharedNativePixmaps[pixmapNdx].second));
m_sharedNativePixmaps[pixmapNdx].second = EGL_NO_SURFACE;
delete m_sharedNativePixmaps[pixmapNdx].first;
m_sharedNativePixmaps[pixmapNdx].first = NULL;
}
m_sharedNativePixmaps.clear();
// Clear windows
for (int windowNdx = 0; windowNdx < (int)m_nativeWindows1.size(); windowNdx++)
{
if (m_nativeWindows1[windowNdx].second != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, m_nativeWindows1[windowNdx].second));
m_nativeWindows1[windowNdx].second = EGL_NO_SURFACE;
delete m_nativeWindows1[windowNdx].first;
m_nativeWindows1[windowNdx].first = NULL;
}
m_nativeWindows1.clear();
for (int windowNdx = 0; windowNdx < (int)m_nativeWindows0.size(); windowNdx++)
{
if (m_nativeWindows0[windowNdx].second != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, m_nativeWindows0[windowNdx].second));
m_nativeWindows0[windowNdx].second = EGL_NO_SURFACE;
delete m_nativeWindows0[windowNdx].first;
m_nativeWindows0[windowNdx].first = NULL;
}
m_nativeWindows0.clear();
for (int windowNdx = 0; windowNdx < (int)m_sharedNativeWindows.size(); windowNdx++)
{
if (m_sharedNativeWindows[windowNdx].second != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, m_sharedNativeWindows[windowNdx].second));
m_sharedNativeWindows[windowNdx].second = EGL_NO_SURFACE;
delete m_sharedNativeWindows[windowNdx].first;
m_sharedNativeWindows[windowNdx].first = NULL;
}
m_sharedNativeWindows.clear();
MultiThreadedTest::deinit();
}
bool MultiThreadedObjectTest::runThread(TestThread &thread)
{
const Library &egl = getLibrary();
if (thread.getId() == 0)
{
EGLint surfaceTypes = 0;
if ((m_types & TYPE_WINDOW) != 0)
surfaceTypes |= EGL_WINDOW_BIT;
if ((m_types & TYPE_PBUFFER) != 0)
surfaceTypes |= EGL_PBUFFER_BIT;
if ((m_types & TYPE_PIXMAP) != 0)
surfaceTypes |= EGL_PIXMAP_BIT;
EGLint configCount;
EGLint attribList[] = {EGL_SURFACE_TYPE, surfaceTypes, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE};
EGLU_CHECK_CALL(egl, chooseConfig(m_display, attribList, &m_config, 1, &configCount));
if (configCount == 0)
TCU_THROW(NotSupportedError, "No usable config found");
}
barrier();
// Create / Destroy Objects
if ((m_types & TYPE_SINGLE_WINDOW) != 0 && (m_types & TYPE_PBUFFER) == 0 && (m_types & TYPE_PIXMAP) == 0 &&
(m_types & TYPE_CONTEXT) == 0)
{
if (thread.getId() == 0)
createDestroyObjects(thread, 1);
}
else
createDestroyObjects(thread, 100);
// Push first threads objects to shared
if (thread.getId() == 0)
pushObjectsToShared(thread);
barrier();
// Push second threads objects to shared
if (thread.getId() == 1)
pushObjectsToShared(thread);
barrier();
// Make queries from shared surfaces
querySetSharedObjects(thread, 100);
barrier();
// Pull surfaces for first thread from shared surfaces
if (thread.getId() == 0)
pullObjectsFromShared(thread, (int)(m_sharedPbuffers.size() / 2), (int)(m_sharedNativePixmaps.size() / 2),
(int)(m_sharedNativeWindows.size() / 2), (int)(m_sharedContexts.size() / 2));
barrier();
// Pull surfaces for second thread from shared surfaces
if (thread.getId() == 1)
pullObjectsFromShared(thread, (int)m_sharedPbuffers.size(), (int)m_sharedNativePixmaps.size(),
(int)m_sharedNativeWindows.size(), (int)m_sharedContexts.size());
barrier();
// Create / Destroy Objects
if ((m_types & TYPE_SINGLE_WINDOW) == 0)
createDestroyObjects(thread, 100);
// Destroy surfaces
destroyObjects(thread);
return true;
}
void MultiThreadedObjectTest::createDestroyObjects(TestThread &thread, int count)
{
const Library &egl = getLibrary();
de::Random &rnd = (thread.getId() == 0 ? m_rnd0 : m_rnd1);
vector<EGLSurface> &pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1);
vector<pair<eglu::NativeWindow *, EGLSurface>> &windows =
(thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1);
vector<pair<eglu::NativePixmap *, EGLSurface>> &pixmaps =
(thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1);
vector<EGLContext> &contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1);
set<Type> objectTypes;
if ((m_types & TYPE_PBUFFER) != 0)
objectTypes.insert(TYPE_PBUFFER);
if ((m_types & TYPE_PIXMAP) != 0)
objectTypes.insert(TYPE_PIXMAP);
if ((m_types & TYPE_WINDOW) != 0)
objectTypes.insert(TYPE_WINDOW);
if ((m_types & TYPE_CONTEXT) != 0)
objectTypes.insert(TYPE_CONTEXT);
for (int createDestroyNdx = 0; createDestroyNdx < count; createDestroyNdx++)
{
bool create;
Type type;
if (pbuffers.size() > 5 && ((m_types & TYPE_PBUFFER) != 0))
{
create = false;
type = TYPE_PBUFFER;
}
else if (windows.size() > 5 && ((m_types & TYPE_WINDOW) != 0))
{
create = false;
type = TYPE_WINDOW;
}
else if (pixmaps.size() > 5 && ((m_types & TYPE_PIXMAP) != 0))
{
create = false;
type = TYPE_PIXMAP;
}
else if (contexts.size() > 5 && ((m_types & TYPE_CONTEXT) != 0))
{
create = false;
type = TYPE_CONTEXT;
}
else if (pbuffers.size() < 3 && ((m_types & TYPE_PBUFFER) != 0))
{
create = true;
type = TYPE_PBUFFER;
}
else if (pixmaps.size() < 3 && ((m_types & TYPE_PIXMAP) != 0))
{
create = true;
type = TYPE_PIXMAP;
}
else if (contexts.size() < 3 && ((m_types & TYPE_CONTEXT) != 0))
{
create = true;
type = TYPE_CONTEXT;
}
else if (windows.size() < 3 && ((m_types & TYPE_WINDOW) != 0) && ((m_types & TYPE_SINGLE_WINDOW) == 0))
{
create = true;
type = TYPE_WINDOW;
}
else if (windows.empty() && (m_hasWindow == 0) && ((m_types & TYPE_WINDOW) != 0) &&
((m_types & TYPE_SINGLE_WINDOW) != 0))
{
create = true;
type = TYPE_WINDOW;
}
else
{
create = rnd.getBool();
if (!create && windows.empty())
objectTypes.erase(TYPE_WINDOW);
type = rnd.choose<Type>(objectTypes.begin(), objectTypes.end());
}
if (create)
{
switch (type)
{
case TYPE_PBUFFER:
{
EGLSurface surface;
const EGLint attributes[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64,
EGL_NONE};
surface = egl.createPbufferSurface(m_display, m_config, attributes);
thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreatePbufferSurface(" << m_display
<< ", " << m_config << ", { EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE })"
<< ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglCreatePbufferSurface()");
pbuffers.push_back(surface);
break;
}
case TYPE_WINDOW:
{
const eglu::NativeWindowFactory &windowFactory =
eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
if ((m_types & TYPE_SINGLE_WINDOW) != 0)
{
if (deAtomicCompareExchange32(&m_hasWindow, 0, 1) == 0)
{
eglu::NativeWindow *window = DE_NULL;
EGLSurface surface = EGL_NO_SURFACE;
try
{
window = windowFactory.createWindow(
&m_eglTestCtx.getNativeDisplay(), m_display, m_config, DE_NULL,
eglu::WindowParams(64, 64, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
surface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, m_display,
m_config, DE_NULL);
thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreateWindowSurface()"
<< ThreadLog::EndMessage;
windows.push_back(std::make_pair(window, surface));
}
catch (const std::exception &)
{
if (surface != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, surface));
delete window;
m_hasWindow = 0;
throw;
}
}
else
{
createDestroyNdx--;
}
}
else
{
eglu::NativeWindow *window = DE_NULL;
EGLSurface surface = EGL_NO_SURFACE;
try
{
window = windowFactory.createWindow(
&m_eglTestCtx.getNativeDisplay(), m_display, m_config, DE_NULL,
eglu::WindowParams(64, 64, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
surface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, m_display,
m_config, DE_NULL);
thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreateWindowSurface()"
<< ThreadLog::EndMessage;
windows.push_back(std::make_pair(window, surface));
}
catch (const std::exception &)
{
if (surface != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, surface));
delete window;
throw;
}
}
break;
}
case TYPE_PIXMAP:
{
const eglu::NativePixmapFactory &pixmapFactory =
eglu::selectNativePixmapFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
eglu::NativePixmap *pixmap = DE_NULL;
EGLSurface surface = EGL_NO_SURFACE;
try
{
pixmap = pixmapFactory.createPixmap(&m_eglTestCtx.getNativeDisplay(), m_display, m_config, DE_NULL,
64, 64);
surface = eglu::createPixmapSurface(m_eglTestCtx.getNativeDisplay(), *pixmap, m_display, m_config,
DE_NULL);
thread.getLog() << ThreadLog::BeginMessage << surface << " = eglCreatePixmapSurface()"
<< ThreadLog::EndMessage;
pixmaps.push_back(std::make_pair(pixmap, surface));
}
catch (const std::exception &)
{
if (surface != EGL_NO_SURFACE)
EGLU_CHECK_CALL(egl, destroySurface(m_display, surface));
delete pixmap;
throw;
}
break;
}
case TYPE_CONTEXT:
{
EGLContext context;
EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API));
thread.getLog() << ThreadLog::BeginMessage << "eglBindAPI(EGL_OPENGL_ES_API)" << ThreadLog::EndMessage;
const EGLint attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
context = egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attributes);
thread.getLog() << ThreadLog::BeginMessage << context << " = eglCreateContext(" << m_display << ", "
<< m_config << ", EGL_NO_CONTEXT, { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE })"
<< ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglCreateContext()");
contexts.push_back(context);
break;
}
default:
DE_ASSERT(false);
}
}
else
{
switch (type)
{
case TYPE_PBUFFER:
{
const int pbufferNdx = rnd.getInt(0, (int)(pbuffers.size() - 1));
EGLBoolean result;
result = egl.destroySurface(m_display, pbuffers[pbufferNdx]);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglDestroySurface(" << m_display << ", "
<< pbuffers[pbufferNdx] << ")" << ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglDestroySurface()");
pbuffers.erase(pbuffers.begin() + pbufferNdx);
break;
}
case TYPE_WINDOW:
{
const int windowNdx = rnd.getInt(0, (int)(windows.size() - 1));
thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", "
<< windows[windowNdx].second << ")" << ThreadLog::EndMessage;
EGLU_CHECK_CALL(egl, destroySurface(m_display, windows[windowNdx].second));
windows[windowNdx].second = EGL_NO_SURFACE;
delete windows[windowNdx].first;
windows[windowNdx].first = DE_NULL;
windows.erase(windows.begin() + windowNdx);
if ((m_types & TYPE_SINGLE_WINDOW) != 0)
m_hasWindow = 0;
break;
}
case TYPE_PIXMAP:
{
const int pixmapNdx = rnd.getInt(0, (int)(pixmaps.size() - 1));
thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", "
<< pixmaps[pixmapNdx].second << ")" << ThreadLog::EndMessage;
EGLU_CHECK_CALL(egl, destroySurface(m_display, pixmaps[pixmapNdx].second));
pixmaps[pixmapNdx].second = EGL_NO_SURFACE;
delete pixmaps[pixmapNdx].first;
pixmaps[pixmapNdx].first = DE_NULL;
pixmaps.erase(pixmaps.begin() + pixmapNdx);
break;
}
case TYPE_CONTEXT:
{
const int contextNdx = rnd.getInt(0, (int)(contexts.size() - 1));
EGLU_CHECK_CALL(egl, destroyContext(m_display, contexts[contextNdx]));
thread.getLog() << ThreadLog::BeginMessage << "eglDestroyContext(" << m_display << ", "
<< contexts[contextNdx] << ")" << ThreadLog::EndMessage;
contexts.erase(contexts.begin() + contextNdx);
break;
}
default:
DE_ASSERT(false);
}
}
}
}
void MultiThreadedObjectTest::pushObjectsToShared(TestThread &thread)
{
vector<EGLSurface> &pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1);
vector<pair<eglu::NativeWindow *, EGLSurface>> &windows =
(thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1);
vector<pair<eglu::NativePixmap *, EGLSurface>> &pixmaps =
(thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1);
vector<EGLContext> &contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1);
for (int pbufferNdx = 0; pbufferNdx < (int)pbuffers.size(); pbufferNdx++)
m_sharedPbuffers.push_back(pbuffers[pbufferNdx]);
pbuffers.clear();
for (int windowNdx = 0; windowNdx < (int)windows.size(); windowNdx++)
m_sharedNativeWindows.push_back(windows[windowNdx]);
windows.clear();
for (int pixmapNdx = 0; pixmapNdx < (int)pixmaps.size(); pixmapNdx++)
m_sharedNativePixmaps.push_back(pixmaps[pixmapNdx]);
pixmaps.clear();
for (int contextNdx = 0; contextNdx < (int)contexts.size(); contextNdx++)
m_sharedContexts.push_back(contexts[contextNdx]);
contexts.clear();
}
void MultiThreadedObjectTest::pullObjectsFromShared(TestThread &thread, int pbufferCount, int pixmapCount,
int windowCount, int contextCount)
{
de::Random &rnd = (thread.getId() == 0 ? m_rnd0 : m_rnd1);
vector<EGLSurface> &pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1);
vector<pair<eglu::NativeWindow *, EGLSurface>> &windows =
(thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1);
vector<pair<eglu::NativePixmap *, EGLSurface>> &pixmaps =
(thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1);
vector<EGLContext> &contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1);
for (int pbufferNdx = 0; pbufferNdx < pbufferCount; pbufferNdx++)
{
const int ndx = rnd.getInt(0, (int)(m_sharedPbuffers.size() - 1));
pbuffers.push_back(m_sharedPbuffers[ndx]);
m_sharedPbuffers.erase(m_sharedPbuffers.begin() + ndx);
}
for (int pixmapNdx = 0; pixmapNdx < pixmapCount; pixmapNdx++)
{
const int ndx = rnd.getInt(0, (int)(m_sharedNativePixmaps.size() - 1));
pixmaps.push_back(m_sharedNativePixmaps[ndx]);
m_sharedNativePixmaps.erase(m_sharedNativePixmaps.begin() + ndx);
}
for (int windowNdx = 0; windowNdx < windowCount; windowNdx++)
{
const int ndx = rnd.getInt(0, (int)(m_sharedNativeWindows.size() - 1));
windows.push_back(m_sharedNativeWindows[ndx]);
m_sharedNativeWindows.erase(m_sharedNativeWindows.begin() + ndx);
}
for (int contextNdx = 0; contextNdx < contextCount; contextNdx++)
{
const int ndx = rnd.getInt(0, (int)(m_sharedContexts.size() - 1));
contexts.push_back(m_sharedContexts[ndx]);
m_sharedContexts.erase(m_sharedContexts.begin() + ndx);
}
}
void MultiThreadedObjectTest::querySetSharedObjects(TestThread &thread, int count)
{
const Library &egl = getLibrary();
de::Random &rnd = (thread.getId() == 0 ? m_rnd0 : m_rnd1);
vector<Type> objectTypes;
if ((m_types & TYPE_PBUFFER) != 0)
objectTypes.push_back(TYPE_PBUFFER);
if ((m_types & TYPE_PIXMAP) != 0)
objectTypes.push_back(TYPE_PIXMAP);
if (!m_sharedNativeWindows.empty() && (m_types & TYPE_WINDOW) != 0)
objectTypes.push_back(TYPE_WINDOW);
if ((m_types & TYPE_CONTEXT) != 0)
objectTypes.push_back(TYPE_CONTEXT);
for (int queryNdx = 0; queryNdx < count; queryNdx++)
{
const Type type = rnd.choose<Type>(objectTypes.begin(), objectTypes.end());
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
switch (type)
{
case TYPE_PBUFFER:
surface = m_sharedPbuffers[rnd.getInt(0, (int)(m_sharedPbuffers.size() - 1))];
break;
case TYPE_PIXMAP:
surface = m_sharedNativePixmaps[rnd.getInt(0, (int)(m_sharedNativePixmaps.size() - 1))].second;
break;
case TYPE_WINDOW:
surface = m_sharedNativeWindows[rnd.getInt(0, (int)(m_sharedNativeWindows.size() - 1))].second;
break;
case TYPE_CONTEXT:
context = m_sharedContexts[rnd.getInt(0, (int)(m_sharedContexts.size() - 1))];
break;
default:
DE_ASSERT(false);
}
if (surface != EGL_NO_SURFACE)
{
static const EGLint queryAttributes[] = {EGL_LARGEST_PBUFFER, EGL_HEIGHT, EGL_WIDTH};
const EGLint attribute = queryAttributes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(queryAttributes) - 1)];
EGLBoolean result;
EGLint value;
result = egl.querySurface(m_display, surface, attribute, &value);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglQuerySurface(" << m_display << ", "
<< surface << ", " << attribute << ", " << value << ")" << ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglQuerySurface()");
}
else if (context != EGL_NO_CONTEXT)
{
static const EGLint attributes[] = {EGL_CONFIG_ID, EGL_CONTEXT_CLIENT_TYPE, EGL_CONTEXT_CLIENT_VERSION,
EGL_RENDER_BUFFER};
const EGLint attribute = attributes[rnd.getInt(0, DE_LENGTH_OF_ARRAY(attributes) - 1)];
EGLint value;
EGLBoolean result;
result = egl.queryContext(m_display, context, attribute, &value);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglQueryContext(" << m_display << ", "
<< context << ", " << attribute << ", " << value << ")" << ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglQueryContext()");
}
else
DE_ASSERT(false);
}
}
void MultiThreadedObjectTest::destroyObjects(TestThread &thread)
{
const Library &egl = getLibrary();
vector<EGLSurface> &pbuffers = (thread.getId() == 0 ? m_pbuffers0 : m_pbuffers1);
vector<pair<eglu::NativeWindow *, EGLSurface>> &windows =
(thread.getId() == 0 ? m_nativeWindows0 : m_nativeWindows1);
vector<pair<eglu::NativePixmap *, EGLSurface>> &pixmaps =
(thread.getId() == 0 ? m_nativePixmaps0 : m_nativePixmaps1);
vector<EGLContext> &contexts = (thread.getId() == 0 ? m_contexts0 : m_contexts1);
for (int pbufferNdx = 0; pbufferNdx < (int)pbuffers.size(); pbufferNdx++)
{
if (pbuffers[pbufferNdx] != EGL_NO_SURFACE)
{
// Destroy EGLSurface
EGLBoolean result;
result = egl.destroySurface(m_display, pbuffers[pbufferNdx]);
thread.getLog() << ThreadLog::BeginMessage << result << " = eglDestroySurface(" << m_display << ", "
<< pbuffers[pbufferNdx] << ")" << ThreadLog::EndMessage;
EGLU_CHECK_MSG(egl, "eglDestroySurface()");
pbuffers[pbufferNdx] = EGL_NO_SURFACE;
}
}
pbuffers.clear();
for (int windowNdx = 0; windowNdx < (int)windows.size(); windowNdx++)
{
if (windows[windowNdx].second != EGL_NO_SURFACE)
{
thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", "
<< windows[windowNdx].second << ")" << ThreadLog::EndMessage;
EGLU_CHECK_CALL(egl, destroySurface(m_display, windows[windowNdx].second));
windows[windowNdx].second = EGL_NO_SURFACE;
}
if (windows[windowNdx].first)
{
delete windows[windowNdx].first;
windows[windowNdx].first = NULL;
}
}
windows.clear();
for (int pixmapNdx = 0; pixmapNdx < (int)pixmaps.size(); pixmapNdx++)
{
if (pixmaps[pixmapNdx].first != EGL_NO_SURFACE)
{
thread.getLog() << ThreadLog::BeginMessage << "eglDestroySurface(" << m_display << ", "
<< pixmaps[pixmapNdx].second << ")" << ThreadLog::EndMessage;
EGLU_CHECK_CALL(egl, destroySurface(m_display, pixmaps[pixmapNdx].second));
pixmaps[pixmapNdx].second = EGL_NO_SURFACE;
}
if (pixmaps[pixmapNdx].first)
{
delete pixmaps[pixmapNdx].first;
pixmaps[pixmapNdx].first = NULL;
}
}
pixmaps.clear();
for (int contextNdx = 0; contextNdx < (int)contexts.size(); contextNdx++)
{
if (contexts[contextNdx] != EGL_NO_CONTEXT)
{
EGLU_CHECK_CALL(egl, destroyContext(m_display, contexts[contextNdx]));
thread.getLog() << ThreadLog::BeginMessage << "eglDestroyContext(" << m_display << ", "
<< contexts[contextNdx] << ")" << ThreadLog::EndMessage;
contexts[contextNdx] = EGL_NO_CONTEXT;
}
}
contexts.clear();
}
MultiThreadedTests::MultiThreadedTests(EglTestContext &context)
: TestCaseGroup(context, "multithread", "Multithreaded EGL tests")
{
}
void MultiThreadedTests::init(void)
{
// Config tests
addChild(new MultiThreadedConfigTest(m_eglTestCtx, "config", "", 30, 30, 30));
// Object tests
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer", "", MultiThreadedObjectTest::TYPE_PBUFFER));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap", "", MultiThreadedObjectTest::TYPE_PIXMAP));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "window", "", MultiThreadedObjectTest::TYPE_WINDOW));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "single_window", "",
MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "context", "", MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_PIXMAP));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_window", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_WINDOW));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_single_window", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW));
addChild(
new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_context", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_window", "",
MultiThreadedObjectTest::TYPE_PIXMAP | MultiThreadedObjectTest::TYPE_WINDOW));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_single_window", "",
MultiThreadedObjectTest::TYPE_PIXMAP | MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_context", "",
MultiThreadedObjectTest::TYPE_PIXMAP | MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "window_context", "",
MultiThreadedObjectTest::TYPE_WINDOW | MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "single_window_context", "",
MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW |
MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_window", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_PIXMAP |
MultiThreadedObjectTest::TYPE_WINDOW));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_single_window", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_PIXMAP |
MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_context", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_PIXMAP |
MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_window_context", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_single_window_context", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW |
MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_window_context", "",
MultiThreadedObjectTest::TYPE_PIXMAP | MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pixmap_single_window_context", "",
MultiThreadedObjectTest::TYPE_PIXMAP | MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW |
MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_window_context", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_PIXMAP |
MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_CONTEXT));
addChild(new MultiThreadedObjectTest(m_eglTestCtx, "pbuffer_pixmap_single_window_context", "",
MultiThreadedObjectTest::TYPE_PBUFFER | MultiThreadedObjectTest::TYPE_PIXMAP |
MultiThreadedObjectTest::TYPE_WINDOW |
MultiThreadedObjectTest::TYPE_SINGLE_WINDOW |
MultiThreadedObjectTest::TYPE_CONTEXT));
}
} // namespace egl
} // namespace deqp