Path: blob/main_old/src/tests/egl_tests/EGLContextASANTest.cpp
1693 views
//1// Copyright 2020 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//5// EGLContextASANTest.cpp:6// Tests relating to ASAN errors regarding context.78#include <gtest/gtest.h>910#include "test_utils/ANGLETest.h"11#include "test_utils/angle_test_configs.h"12#include "test_utils/gl_raii.h"13#include "util/EGLWindow.h"1415#include <condition_variable>16#include <mutex>17#include <thread>1819using namespace angle;2021namespace22{2324EGLBoolean SafeDestroyContext(EGLDisplay display, EGLContext &context)25{26EGLBoolean result = EGL_TRUE;27if (context != EGL_NO_CONTEXT)28{29result = eglDestroyContext(display, context);30context = EGL_NO_CONTEXT;31}32return result;33}3435class EGLContextASANTest : public ANGLETest36{37public:38EGLContextASANTest() {}39};4041// Tests that creating resources works after freeing the share context.42TEST_P(EGLContextASANTest, DestroyContextInUse)43{44ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());4546EGLDisplay display = getEGLWindow()->getDisplay();47EGLConfig config = getEGLWindow()->getConfig();48EGLSurface surface = getEGLWindow()->getSurface();4950const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION,51getEGLWindow()->getClientMajorVersion(), EGL_NONE};5253EGLContext context = eglCreateContext(display, config, nullptr, contextAttribs);54ASSERT_EGL_SUCCESS();55ASSERT_TRUE(context != EGL_NO_CONTEXT);5657// Synchronization tools to ensure the two threads are interleaved as designed by this test.58std::mutex mutex;59std::condition_variable condVar;6061enum class Step62{63Start,64Thread1Draw,65Thread0Delete,66Thread1Draw2,67Finish,68Abort,69};70Step currentStep = Step::Start;7172// Helper functions to synchronize the threads so that the operations are executed in the73// specific order the test is written for.74auto waitForStep = [&](Step waitStep) -> bool {75std::unique_lock<std::mutex> lock(mutex);76while (currentStep != waitStep)77{78// If necessary, abort execution as the other thread has encountered a GL error.79if (currentStep == Step::Abort)80{81return false;82}83condVar.wait(lock);84}8586return true;87};88auto nextStep = [&](Step newStep) {89{90std::unique_lock<std::mutex> lock(mutex);91currentStep = newStep;92}93condVar.notify_one();94};9596class AbortOnFailure97{98public:99AbortOnFailure(Step *currentStep, std::mutex *mutex, std::condition_variable *condVar)100: mCurrentStep(currentStep), mMutex(mutex), mCondVar(condVar)101{}102103~AbortOnFailure()104{105bool isAborting = false;106{107std::unique_lock<std::mutex> lock(*mMutex);108isAborting = *mCurrentStep != Step::Finish;109110if (isAborting)111{112*mCurrentStep = Step::Abort;113}114}115mCondVar->notify_all();116}117118private:119Step *mCurrentStep;120std::mutex *mMutex;121std::condition_variable *mCondVar;122};123124std::thread deletingThread = std::thread([&]() {125AbortOnFailure abortOnFailure(¤tStep, &mutex, &condVar);126127EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));128EXPECT_EGL_SUCCESS();129EXPECT_GL_NO_ERROR();130131// Wait for other thread to draw132ASSERT_TRUE(waitForStep(Step::Thread1Draw));133134// Delete the context, if implemented properly this is a no-op because the context is135// current in another thread.136SafeDestroyContext(display, context);137138// Wait for the other thread to use context again139nextStep(Step::Thread0Delete);140ASSERT_TRUE(waitForStep(Step::Finish));141});142143std::thread continuingThread = std::thread([&]() {144EGLContext localContext = context;145AbortOnFailure abortOnFailure(¤tStep, &mutex, &condVar);146147EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, localContext));148EXPECT_EGL_SUCCESS();149150constexpr GLsizei kTexSize = 1;151const GLColor kTexData = GLColor::red;152153GLTexture tex;154glBindTexture(GL_TEXTURE_2D, tex);155glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kTexSize, kTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,156&kTexData);157glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);158glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);159160GLProgram program;161program.makeRaster(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());162ASSERT_TRUE(program.valid());163164// Draw using the texture.165drawQuad(program.get(), essl1_shaders::PositionAttrib(), 0.5f);166167EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, localContext));168EXPECT_EGL_SUCCESS();169170// Wait for the other thread to delete the context.171nextStep(Step::Thread1Draw);172ASSERT_TRUE(waitForStep(Step::Thread0Delete));173174EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, localContext));175EXPECT_EGL_SUCCESS();176177// Draw again. If the context has been inappropriately deleted in thread0 this will cause a178// use-after-free error.179drawQuad(program.get(), essl1_shaders::PositionAttrib(), 0.5f);180181nextStep(Step::Finish);182183EXPECT_EGL_TRUE(eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));184EXPECT_EGL_SUCCESS();185});186187deletingThread.join();188continuingThread.join();189190ASSERT_NE(currentStep, Step::Abort);191192// cleanup193ASSERT_GL_NO_ERROR();194}195} // anonymous namespace196197GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLContextASANTest);198ANGLE_INSTANTIATE_TEST(EGLContextASANTest,199ES2_D3D9(),200ES2_D3D11(),201ES3_D3D11(),202ES2_OPENGL(),203ES3_OPENGL(),204ES2_VULKAN(),205ES3_VULKAN());206207208