blob: 1648fe59a7b43e8259c4588eb5e684af0e845e25 [file] [log] [blame]
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dawn/native/opengl/UtilsEGL.h"
#include <string>
#include <vector>
#include "dawn/native/opengl/DeviceGL.h"
#include "dawn/native/opengl/EGLFunctions.h"
#include "dawn/native/opengl/PhysicalDeviceGL.h"
namespace dawn::native::opengl {
namespace {
std::vector<EGLAttrib> ConvertEGLIntParameterListToEGLAttrib(const EGLint* intAttribs) {
std::vector<EGLAttrib> attribs;
if (intAttribs) {
for (const EGLint* curAttrib = intAttribs; *curAttrib != EGL_NONE; curAttrib++) {
attribs.push_back(static_cast<EGLAttrib>(*curAttrib));
}
}
attribs.push_back(EGL_NONE);
return attribs;
}
} // namespace
const char* EGLErrorAsString(EGLint error) {
switch (error) {
case EGL_SUCCESS:
return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED:
return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS:
return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC:
return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE:
return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONTEXT:
return "EGL_BAD_CONTEXT";
case EGL_BAD_CONFIG:
return "EGL_BAD_CONFIG";
case EGL_BAD_CURRENT_SURFACE:
return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY:
return "EGL_BAD_DISPLAY";
case EGL_BAD_SURFACE:
return "EGL_BAD_SURFACE";
case EGL_BAD_MATCH:
return "EGL_BAD_MATCH";
case EGL_BAD_PARAMETER:
return "EGL_BAD_PARAMETER";
case EGL_BAD_NATIVE_PIXMAP:
return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW:
return "EGL_BAD_NATIVE_WINDOW";
case EGL_CONTEXT_LOST:
return "EGL_CONTEXT_LOST";
default:
return "<Unknown EGL error>";
}
}
MaybeError CheckEGL(const EGLFunctions& egl, EGLBoolean result, const char* context) {
if (result != EGL_FALSE) [[likely]] {
return {};
}
EGLint error = egl.GetError();
std::string message = std::string(context) + " failed with " + EGLErrorAsString(error);
if (error == EGL_BAD_ALLOC) {
return DAWN_OUT_OF_MEMORY_ERROR(message);
} else if (error == EGL_CONTEXT_LOST) {
return DAWN_DEVICE_LOST_ERROR(message);
} else {
return DAWN_INTERNAL_ERROR(message);
}
}
ResultOrError<Ref<WrappedEGLSync>> WrappedEGLSync::Create(DisplayEGL* display,
const OpenGLFunctions&,
EGLenum type,
const EGLint* attribs) {
const EGLFunctions& egl = display->egl.get();
EGLSyncKHR sync = EGL_NO_SYNC;
// We don't use OpenGLFunctions struct. However eglCreateSync requires a current context,
// so a OpenGLFunctions parameter restricts the caller to call this inside Device's
// EnqueueGL/ExecuteGL.
if (egl.HasExt(EGLExt::FenceSync)) {
sync = egl.CreateSyncKHR(display->GetDisplay(), type, attribs);
} else {
DAWN_ASSERT(egl.IsAtLeastVersion(1, 5));
std::vector<EGLAttrib> convertedAttribs = ConvertEGLIntParameterListToEGLAttrib(attribs);
sync = egl.CreateSync(display->GetDisplay(), type, convertedAttribs.data());
}
DAWN_TRY(CheckEGL(egl, sync != EGL_NO_SYNC, "eglCreateSync"));
return AcquireRef(new WrappedEGLSync(display, sync, true));
}
ResultOrError<Ref<WrappedEGLSync>> WrappedEGLSync::AcquireExternal(DisplayEGL* display,
EGLSync sync) {
const EGLFunctions& egl = display->egl.get();
// Query a property of the sync object to verify that it's valid and associated with this
// EGLDisplay.
EGLBoolean queryResult = 0;
if (egl.HasExt(EGLExt::FenceSync)) {
EGLint syncType = 0;
queryResult = egl.GetSyncAttribKHR(display->GetDisplay(), sync, EGL_SYNC_TYPE, &syncType);
} else {
DAWN_ASSERT(egl.IsAtLeastVersion(1, 5));
EGLAttrib syncType = 0;
queryResult = egl.GetSyncAttrib(display->GetDisplay(), sync, EGL_SYNC_TYPE, &syncType);
}
DAWN_TRY(CheckEGL(egl, queryResult, "eglGetSyncAttrib"));
return AcquireRef(new WrappedEGLSync(display, sync, false));
}
WrappedEGLSync::WrappedEGLSync(DisplayEGL* display, EGLSync sync, bool ownsSync)
: mDisplay(display), mSync(sync), mOwnsSync(ownsSync) {
DAWN_ASSERT(mDisplay != nullptr);
DAWN_ASSERT(mSync != EGL_NO_SYNC);
}
WrappedEGLSync::~WrappedEGLSync() {
if (mOwnsSync) {
const EGLFunctions& egl = mDisplay->egl.get();
if (egl.HasExt(EGLExt::FenceSync)) {
egl.DestroySyncKHR(mDisplay->GetDisplay(), mSync);
} else {
DAWN_ASSERT(egl.IsAtLeastVersion(1, 5));
egl.DestroySync(mDisplay->GetDisplay(), mSync);
}
}
}
EGLSync WrappedEGLSync::Get() const {
return mSync;
}
MaybeError WrappedEGLSync::Signal(const OpenGLFunctions&, EGLenum mode) {
const EGLFunctions& egl = mDisplay->egl.get();
DAWN_ASSERT(egl.HasExt(EGLExt::ReusableSync));
DAWN_TRY(CheckEGL(egl, egl.SignalSync(mDisplay->GetDisplay(), mSync, mode), "eglSignalSync"));
return {};
}
ResultOrError<EGLenum> WrappedEGLSync::ClientWait(const OpenGLFunctions&,
EGLint flags,
Nanoseconds timeout) {
const EGLFunctions& egl = mDisplay->egl.get();
EGLenum result = EGL_FALSE;
if (egl.HasExt(EGLExt::FenceSync)) {
result = egl.ClientWaitSyncKHR(mDisplay->GetDisplay(), mSync, flags, uint64_t(timeout));
} else {
DAWN_ASSERT(egl.IsAtLeastVersion(1, 5));
result = egl.ClientWaitSync(mDisplay->GetDisplay(), mSync, flags, uint64_t(timeout));
}
DAWN_TRY(CheckEGL(egl, result != EGL_FALSE, "eglClientWaitSync"));
return result;
}
MaybeError WrappedEGLSync::Wait(const OpenGLFunctions&) {
const EGLFunctions& egl = mDisplay->egl.get();
DAWN_ASSERT(egl.HasExt(EGLExt::WaitSync));
constexpr EGLint flags = 0;
DAWN_TRY(CheckEGL(egl, egl.WaitSync(mDisplay->GetDisplay(), mSync, flags), "eglWaitSync"));
return {};
}
ResultOrError<EGLint> WrappedEGLSync::DupFD(const OpenGLFunctions&) {
const EGLFunctions& egl = mDisplay->egl.get();
DAWN_ASSERT(egl.HasExt(EGLExt::NativeFenceSync));
EGLint fd = egl.DupNativeFenceFD(mDisplay->GetDisplay(), mSync);
DAWN_TRY(CheckEGL(egl, fd != EGL_NO_NATIVE_FENCE_FD_ANDROID, "eglDupNativeFenceFDANDROID"));
return fd;
}
} // namespace dawn::native::opengl