From 3c333eeab931658b5637cadc56644d1c5464bf23 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 8 May 2018 18:36:20 +0000 Subject: Revert "[RenderEngine] Add PQ/HLG data space support." This reverts commit 0589adcdc1b1265dbae14ebb2e955907ee88da9d. Reason for revert: Breaks Photos in wide color gamut. BUG: 79400076 BUG: 79400707 Change-Id: I57aa170550efa3570f62e9d54b3fb88191ed08c6 (cherry picked from commit 79af36fab456c187236b8a64cc1882df7df4ed68) --- .../surfaceflinger/RenderEngine/ProgramCache.cpp | 230 +++++++-------------- 1 file changed, 78 insertions(+), 152 deletions(-) diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index 57a772b047..5f09ac0d9b 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -233,177 +233,103 @@ void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) { } // Generate OOTF that modifies the relative scence light to relative display light. -void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { - // When HDR and non-HDR contents are mixed, or different types of HDR contents are - // mixed, we will do a transcoding process to transcode the input content to output - // content. Currently, the following conversions handled, they are: - // * SDR -> HLG - // * SDR -> PQ - // * HLG -> PQ - - // Convert relative light to absolute light. - switch (needs.getInputTF()) { +void ProgramCache::generateOOTF(Formatter& fs, const Key& needs) { + fs << R"__SHADER__( + highp float CalculateY(const highp vec3 color) { + // BT2020 standard uses the unadjusted KR = 0.2627, + // KB = 0.0593 luminance interpretation for RGB conversion. + return color.r * 0.262700 + color.g * 0.677998 + color.b * 0.059302; + } + )__SHADER__"; + + // Generate OOTF that modifies the relative display light. + switch(needs.getInputTF()) { case Key::INPUT_TF_ST2084: fs << R"__SHADER__( - highp vec3 ScaleLuminance(color) { - return color * 10000.0; + highp vec3 OOTF(const highp vec3 color) { + const float maxLumi = 10000.0; + const float maxMasteringLumi = 1000.0; + const float maxContentLumi = 1000.0; + const float maxInLumi = min(maxMasteringLumi, maxContentLumi); + float maxOutLumi = displayMaxLuminance; + + // Calculate Y value in XYZ color space. + float colorY = CalculateY(color); + + // convert to nits first + float nits = colorY * maxLumi; + + // clamp to max input luminance + nits = clamp(nits, 0.0, maxInLumi); + + // scale [0.0, maxInLumi] to [0.0, maxOutLumi] + if (maxInLumi <= maxOutLumi) { + nits *= maxOutLumi / maxInLumi; + } else { + // three control points + const float x0 = 10.0; + const float y0 = 17.0; + float x1 = maxOutLumi * 0.75; + float y1 = x1; + float x2 = x1 + (maxInLumi - x1) / 2.0; + float y2 = y1 + (maxOutLumi - y1) * 0.75; + + // horizontal distances between the last three control points + float h12 = x2 - x1; + float h23 = maxInLumi - x2; + // tangents at the last three control points + float m1 = (y2 - y1) / h12; + float m3 = (maxOutLumi - y2) / h23; + float m2 = (m1 + m3) / 2.0; + + if (nits < x0) { + // scale [0.0, x0] to [0.0, y0] linearly + const float slope = y0 / x0; + nits *= slope; + } else if (nits < x1) { + // scale [x0, x1] to [y0, y1] linearly + float slope = (y1 - y0) / (x1 - x0); + nits = y0 + (nits - x0) * slope; + } else if (nits < x2) { + // scale [x1, x2] to [y1, y2] using Hermite interp + float t = (nits - x1) / h12; + nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + + (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; + } else { + // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp + float t = (nits - x2) / h23; + nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + + (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; + } + } + + // convert back to [0.0, 1.0] + float targetY = nits / maxOutLumi; + return color * (targetY / max(1e-6, colorY)); } )__SHADER__"; break; case Key::INPUT_TF_HLG: fs << R"__SHADER__( - highp vec3 ScaleLuminance(color) { + highp vec3 OOTF(const highp vec3 color) { + const float maxOutLumi = 500.0; + const float gamma = 1.2 + 0.42 * log(maxOutLumi / 1000.0) / log(10.0); // The formula is: // alpha * pow(Y, gamma - 1.0) * color + beta; - // where alpha is 1000.0, gamma is 1.2, beta is 0.0. - return color * 1000.0 * pow(color.y, 0.2); + // where alpha is 1.0, beta is 0.0 as recommended in + // Rec. ITU-R BT.2100-1 TABLE 5. + return pow(CalculateY(color), gamma - 1.0) * color; } )__SHADER__"; break; default: fs << R"__SHADER__( - highp vec3 ScaleLuminance(color) { - return color * displayMaxLuminance; - } - )__SHADER__"; - break; - } - - // Tone map absolute light to display luminance range. - switch (needs.getInputTF()) { - case Key::INPUT_TF_ST2084: - case Key::INPUT_TF_HLG: - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_HLG: - // Right now when mixed PQ and HLG contents are presented, - // HLG content will always be converted to PQ. However, for - // completeness, we simply clamp the value to [0.0, 1000.0]. - fs << R"__SHADER__( - highp vec3 ToneMap(color) { - return clamp(color, 0.0, 1000.0); - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 ToneMap(color) { - return color; - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 ToneMap(color) { - const float maxMasteringLumi = 1000.0; - const float maxContentLumi = 1000.0; - const float maxInLumi = min(maxMasteringLumi, maxContentLumi); - float maxOutLumi = displayMaxLuminance; - - float nits = color.y; - - // clamp to max input luminance - nits = clamp(nits, 0.0, maxInLumi); - - // scale [0.0, maxInLumi] to [0.0, maxOutLumi] - if (maxInLumi <= maxOutLumi) { - nits *= maxOutLumi / maxInLumi; - } else { - // three control points - const float x0 = 10.0; - const float y0 = 17.0; - float x1 = maxOutLumi * 0.75; - float y1 = x1; - float x2 = x1 + (maxInLumi - x1) / 2.0; - float y2 = y1 + (maxOutLumi - y1) * 0.75; - - // horizontal distances between the last three control points - const float h12 = x2 - x1; - const float h23 = maxInLumi - x2; - // tangents at the last three control points - const float m1 = (y2 - y1) / h12; - const float m3 = (maxOutLumi - y2) / h23; - const float m2 = (m1 + m3) / 2.0; - - if (nits < x0) { - // scale [0.0, x0] to [0.0, y0] linearly - const float slope = y0 / x0; - nits *= slope; - } else if (nits < x1) { - // scale [x0, x1] to [y0, y1] linearly - const float slope = (y1 - y0) / (x1 - x0); - nits = y0 + (nits - x0) * slope; - } else if (nits < x2) { - // scale [x1, x2] to [y1, y2] using Hermite interp - float t = (nits - x1) / h12; - nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + - (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; - } else { - // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp - float t = (nits - x2) / h23; - nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + - (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; - } - } - - return color * (nits / max(1e-6, color.y)); - } - )__SHADER__"; - break; - } - break; - default: - // TODO(73825729) We need to revert the tone mapping in - // hardware composer properly. - fs << R"__SHADER__( - highp vec3 ToneMap(color) { + highp vec3 OOTF(const highp vec3 color) { return color; } )__SHADER__"; break; } - - // convert absolute light to relative light. - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(color) { - return color / 10000.0; - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_HLG: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(color) { - return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(color) { - return color / displayMaxLuminance; - } - )__SHADER__"; - break; - } - - if (needs.getInputTF() == needs.getOutputTF() || - (needs.getInputTF() == Key::INPUT_TF_LINEAR && - needs.getOutputTF() == Key::OUTPUT_TF_SRGB) || - (needs.getInputTF() == Key::INPUT_TF_SRGB && - needs.getOutputTF() == Key::OUTPUT_TF_LINEAR)) { - fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - return color; - } - )__SHADER__"; - } else { - fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - return NormalizeLuminance(ToneMap(ScaleLuminance(color))); - } - )__SHADER__"; - } } // Generate OETF that converts relative display light to signal values, -- cgit v1.2.3-59-g8ed1b From 24b1caf5e68d44d40ec4fc4bb43a5e8c217039f2 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 9 Aug 2018 14:06:58 -0700 Subject: Revert "SF: Updating permissions checking in Surface Flinger." This reverts commit e243771083d10fab0a7df5cc785f9a231dcc193b. Reason for revert: Breaks eglCreateWindowSurface, see b/112339582 BUG: 112339582 Test: Build, flash, can't reproduce bug Change-Id: I393f39efd7742fd3be7b877341d55bd4fc2942cc (cherry picked from commit e70e129fcb2635d48582ecf4ffda8d54b76cc146) --- libs/gui/include/gui/ISurfaceComposer.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 107 +++----- services/surfaceflinger/tests/Android.bp | 1 - services/surfaceflinger/tests/Credentials_test.cpp | 300 --------------------- .../tests/SurfaceFlinger_test.filter | 2 +- 5 files changed, 46 insertions(+), 370 deletions(-) delete mode 100644 services/surfaceflinger/tests/Credentials_test.cpp diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 98ec33888d..e40157206d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -220,12 +220,12 @@ public: class BnSurfaceComposer: public BnInterface { public: - enum ISurfaceComposerTag { + enum { // Note: BOOT_FINISHED must remain this value, it is called from // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, - CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check + UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC CREATE_DISPLAY_EVENT_CONNECTION, CREATE_DISPLAY, DESTROY_DISPLAY, @@ -236,7 +236,7 @@ public: GET_DISPLAY_CONFIGS, GET_ACTIVE_CONFIG, SET_ACTIVE_CONFIG, - CONNECT_DISPLAY_UNUSED, // unused, fails permissions check + CONNECT_DISPLAY, CAPTURE_SCREEN, CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8310455ac5..1c12bd5b96 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1221,6 +1221,15 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) const NO_THREAD_SAFETY_ANALYSIS { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + // Try to acquire a lock for 1s, fail gracefully const status_t err = mStateLock.timedLock(s2ns(1)); const bool locked = (err == NO_ERROR); @@ -3367,8 +3376,9 @@ bool callingThreadHasUnscopedSurfaceFlingerAccess() { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && - !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { + !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { return false; } return true; @@ -4554,64 +4564,51 @@ void SurfaceFlinger::updateColorMatrixLocked() { } status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { -#pragma clang diagnostic push -#pragma clang diagnostic error "-Wswitch-enum" - switch (static_cast(code)) { - // These methods should at minimum make sure that the client requested - // access to SF. - case AUTHENTICATE_SURFACE: - case BOOT_FINISHED: - case CLEAR_ANIMATION_FRAME_STATS: + switch (code) { case CREATE_CONNECTION: case CREATE_DISPLAY: - case DESTROY_DISPLAY: - case ENABLE_VSYNC_INJECTIONS: - case GET_ACTIVE_COLOR_MODE: + case BOOT_FINISHED: + case CLEAR_ANIMATION_FRAME_STATS: case GET_ANIMATION_FRAME_STATS: + case SET_POWER_MODE: case GET_HDR_CAPABILITIES: - case GET_DISPLAY_COLOR_MODES: - case SET_ACTIVE_CONFIG: - case SET_ACTIVE_COLOR_MODE: + case ENABLE_VSYNC_INJECTIONS: case INJECT_VSYNC: - case SET_POWER_MODE: { + { + // codes that require permission check if (!callingThreadHasUnscopedSurfaceFlingerAccess()) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(), ipc->getCallingUid()); return PERMISSION_DENIED; } + break; + } + /* + * Calling setTransactionState is safe, because you need to have been + * granted a reference to Client* and Handle* to do anything with it. + * + * Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h + */ + case SET_TRANSACTION_STATE: + case CREATE_SCOPED_CONNECTION: + { return OK; } - case GET_LAYER_DEBUG_INFO: { + case CAPTURE_SCREEN: + { + // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { - ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } - return OK; - } - // Used by apps to hook Choreographer to SurfaceFlinger. - case CREATE_DISPLAY_EVENT_CONNECTION: - // The following calls are currently used by clients that do not - // request necessary permissions. However, they do not expose any secret - // information, so it is OK to pass them. - case GET_ACTIVE_CONFIG: - case GET_BUILT_IN_DISPLAY: - case GET_DISPLAY_CONFIGS: - case GET_DISPLAY_STATS: - case GET_SUPPORTED_FRAME_TIMESTAMPS: - // Calling setTransactionState is safe, because you need to have been - // granted a reference to Client* and Handle* to do anything with it. - case SET_TRANSACTION_STATE: - // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h - case CREATE_SCOPED_CONNECTION: { - return OK; + break; } - case CAPTURE_LAYERS: - case CAPTURE_SCREEN: { - // codes that require permission check + case CAPTURE_LAYERS: { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -4620,35 +4617,15 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } - return OK; - } - // The following codes are deprecated and should never be allowed to access SF. - case CONNECT_DISPLAY_UNUSED: - case CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED: { - ALOGE("Attempting to access SurfaceFlinger with unused code: %u", code); - return PERMISSION_DENIED; + break; } } - - // These codes are used for the IBinder protocol to either interrogate the recipient - // side of the transaction for its canonical interface descriptor or to dump its state. - // We let them pass by default. - if (code == IBinder::INTERFACE_TRANSACTION || code == IBinder::DUMP_TRANSACTION) { - return OK; - } - // Numbers from 1000 to 1029 are currently use for backdoors. The code - // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1029) { - ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); - return OK; - } - ALOGE("Permission Denial: SurfaceFlinger did not recognize request code: %u", code); - return PERMISSION_DENIED; -#pragma clang diagnostic pop + return OK; } -status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { +status_t SurfaceFlinger::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ status_t credentialCheck = CheckTransactCodeCredentials(code); if (credentialCheck != OK) { return credentialCheck; diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 604aa7df56..c511c5e753 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -17,7 +17,6 @@ cc_test { defaults: ["surfaceflinger_defaults"], test_suites: ["device-tests"], srcs: [ - "Credentials_test.cpp", "Stress_test.cpp", "SurfaceInterceptor_test.cpp", "Transaction_test.cpp", diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp deleted file mode 100644 index 9ccada55c8..0000000000 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include - -namespace android { - -using Transaction = SurfaceComposerClient::Transaction; - -namespace { -const String8 DISPLAY_NAME("Credentials Display Test"); -const String8 SURFACE_NAME("Test Surface Name"); -const int32_t MIN_LAYER_Z = 0; -const int32_t MAX_LAYER_Z = std::numeric_limits::max(); -const uint32_t ROTATION = 0; -const float FRAME_SCALE = 1.0f; -} // namespace - -/** - * This class tests the CheckCredentials method in SurfaceFlinger. - * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not - * return anything meaningful. - */ -class CredentialsTest : public ::testing::Test { -protected: - void SetUp() override { - // Start the tests as root. - seteuid(AID_ROOT); - - ASSERT_NO_FATAL_FAILURE(initClient()); - } - - void TearDown() override { - mComposerClient->dispose(); - mBGSurfaceControl.clear(); - mComposerClient.clear(); - // Finish the tests as root. - seteuid(AID_ROOT); - } - - sp mDisplay; - sp mVirtualDisplay; - sp mComposerClient; - sp mBGSurfaceControl; - sp mVirtualSurfaceControl; - - void initClient() { - mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - } - - void setupBackgroundSurface() { - mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); - DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(mDisplay, &info); - const ssize_t displayWidth = info.w; - const ssize_t displayHeight = info.h; - - // Background surface - mBGSurfaceControl = - mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(mBGSurfaceControl != nullptr); - ASSERT_TRUE(mBGSurfaceControl->isValid()); - - Transaction t; - t.setDisplayLayerStack(mDisplay, 0); - ASSERT_EQ(NO_ERROR, - t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply()); - } - - void setupVirtualDisplay() { - mVirtualDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); - const ssize_t displayWidth = 100; - const ssize_t displayHeight = 100; - - // Background surface - mVirtualSurfaceControl = - mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(mVirtualSurfaceControl != nullptr); - ASSERT_TRUE(mVirtualSurfaceControl->isValid()); - - Transaction t; - t.setDisplayLayerStack(mVirtualDisplay, 0); - ASSERT_EQ(NO_ERROR, - t.setLayer(mVirtualSurfaceControl, INT_MAX - 3) - .show(mVirtualSurfaceControl) - .apply()); - } - - /** - * Sets UID to imitate Graphic's process. - */ - void setGraphicsUID() { - seteuid(AID_ROOT); - seteuid(AID_GRAPHICS); - } - - /** - * Sets UID to imitate System's process. - */ - void setSystemUID() { - seteuid(AID_ROOT); - seteuid(AID_SYSTEM); - } - - /** - * Sets UID to imitate a process that doesn't have any special privileges in - * our code. - */ - void setBinUID() { - seteuid(AID_ROOT); - seteuid(AID_BIN); - } - - /** - * Template function the check a condition for different types of users: root - * graphics, system, and non-supported user. Root, graphics, and system should - * always equal privilegedValue, and non-supported user should equal unprivilegedValue. - */ - template - void checkWithPrivileges(std::function condition, T privilegedValue, T unprivilegedValue) { - // Check with root. - seteuid(AID_ROOT); - ASSERT_EQ(privilegedValue, condition()); - - // Check as a Graphics user. - setGraphicsUID(); - ASSERT_EQ(privilegedValue, condition()); - - // Check as a system user. - setSystemUID(); - ASSERT_EQ(privilegedValue, condition()); - - // Check as a non-supported user. - setBinUID(); - ASSERT_EQ(unprivilegedValue, condition()); - } -}; - -TEST_F(CredentialsTest, ClientInitTest) { - // Root can init can init the client. - ASSERT_NO_FATAL_FAILURE(initClient()); - - // Graphics can init the client. - setGraphicsUID(); - ASSERT_NO_FATAL_FAILURE(initClient()); - - // System can init the client. - setSystemUID(); - ASSERT_NO_FATAL_FAILURE(initClient()); - - // No one else can init the client. - setBinUID(); - mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_INIT, mComposerClient->initCheck()); -} - -TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) { - std::function condition = [=]() { - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - return (display != nullptr); - }; - // Anyone can access display information. - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); -} - -TEST_F(CredentialsTest, AllowedGetterMethodsTest) { - // The following methods are tested with a UID that is not root, graphics, - // or system, to show that anyone can access them. - setBinUID(); - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - ASSERT_TRUE(display != nullptr); - - DisplayInfo info; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info)); - - Vector configs; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs)); - - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display)); - - ASSERT_NE(static_cast(BAD_VALUE), - SurfaceComposerClient::getActiveColorMode(display)); -} - -TEST_F(CredentialsTest, GetDisplayColorModesTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - Vector outColorModes; - return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -TEST_F(CredentialsTest, SetActiveConfigTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - return SurfaceComposerClient::setActiveConfig(display, 0); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -TEST_F(CredentialsTest, SetActiveColorModeTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -TEST_F(CredentialsTest, CreateSurfaceTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); - const ssize_t displayWidth = info.w; - const ssize_t displayHeight = info.h; - - std::function condition = [=]() { - mBGSurfaceControl = - mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - return mBGSurfaceControl != nullptr && mBGSurfaceControl->isValid(); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); -} - -TEST_F(CredentialsTest, CreateDisplayTest) { - std::function condition = [=]() { - sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); - return testDisplay.get() != nullptr; - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); - - condition = [=]() { - sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false); - return testDisplay.get() != nullptr; - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); -} - -TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) { - setupVirtualDisplay(); - - DisplayInfo info; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info)); - SurfaceComposerClient::destroyDisplay(mVirtualDisplay); - // This test currently fails. TODO(b/112002626): Find a way to properly create - // a display in the test environment, so that destroy display can remove it. - ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info)); -} - -TEST_F(CredentialsTest, CaptureTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - sp outBuffer; - return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, - MIN_LAYER_Z, MAX_LAYER_Z, false, ROTATION, &outBuffer); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -TEST_F(CredentialsTest, CaptureLayersTest) { - setupBackgroundSurface(); - sp outBuffer; - std::function condition = [=]() { - sp outBuffer; - return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE, - &outBuffer); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -/** - * Test for methods accessible directly through SurfaceFlinger: - */ -TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) { - setupBackgroundSurface(); - sp producer = - mBGSurfaceControl->getSurface()->getIGraphicBufferProducer(); - sp sf(ComposerService::getComposerService()); - - std::function condition = [=]() { return sf->authenticateSurfaceTexture(producer); }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); -} -} // namespace android diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter index 1319e12493..731e628bb8 100644 --- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter +++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter @@ -1,5 +1,5 @@ { "presubmit": { - "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize" + "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize" } } -- cgit v1.2.3-59-g8ed1b From 25e1ba1498b93a31cea125d467a12a964329ec91 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 13 Aug 2018 18:55:08 +0000 Subject: Revert "Fix WM input limitations on secondary displays (2/N)" This reverts commit 09cb30e331f60308fa6c9a08088ccbceaa3d4dc3. Reason for revert: null pointer dereference Change-Id: I6091de981d20efccab435c2b50a33c0e2fb899a4 (cherry picked from commit 9224fbadfeeb89fc2f63a7b35573986e5507e1ae) --- services/inputflinger/InputDispatcher.cpp | 171 ++++++++++++------------------ services/inputflinger/InputDispatcher.h | 14 +-- 2 files changed, 70 insertions(+), 115 deletions(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 863e426337..c805805252 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -515,10 +515,9 @@ void InputDispatcher::addRecentEventLocked(EventEntry* entry) { sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y) { // Traverse windows from front to back to find touched window. - const Vector> windowHandles = getWindowHandlesLocked(displayId); - size_t numWindows = windowHandles.size(); + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - sp windowHandle = windowHandles.itemAt(i); + sp windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo->displayId == displayId) { int32_t flags = windowInfo->layoutParamsFlags; @@ -1248,10 +1247,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool isTouchModal = false; // Traverse windows from front to back to find touched window and outside targets. - const Vector> windowHandles = getWindowHandlesLocked(displayId); - size_t numWindows = windowHandles.size(); + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - sp windowHandle = windowHandles.itemAt(i); + sp windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo->displayId != displayId) { continue; // wrong display @@ -1474,10 +1472,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, sp foregroundWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); if (foregroundWindowHandle->getInfo()->hasWallpaper) { - const Vector> windowHandles = getWindowHandlesLocked(displayId); - size_t numWindows = windowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp windowHandle = windowHandles.itemAt(i); + for (size_t i = 0; i < mWindowHandles.size(); i++) { + sp windowHandle = mWindowHandles.itemAt(i); const InputWindowInfo* info = windowHandle->getInfo(); if (info->displayId == displayId && windowHandle->getInfo()->layoutParamsType @@ -1662,10 +1658,9 @@ bool InputDispatcher::checkInjectionPermission(const sp& wind bool InputDispatcher::isWindowObscuredAtPointLocked( const sp& windowHandle, int32_t x, int32_t y) const { int32_t displayId = windowHandle->getInfo()->displayId; - const Vector> windowHandles = getWindowHandlesLocked(displayId); - size_t numWindows = windowHandles.size(); + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - sp otherHandle = windowHandles.itemAt(i); + sp otherHandle = mWindowHandles.itemAt(i); if (otherHandle == windowHandle) { break; } @@ -1683,11 +1678,10 @@ bool InputDispatcher::isWindowObscuredAtPointLocked( bool InputDispatcher::isWindowObscuredLocked(const sp& windowHandle) const { int32_t displayId = windowHandle->getInfo()->displayId; - const Vector> windowHandles = getWindowHandlesLocked(displayId); const InputWindowInfo* windowInfo = windowHandle->getInfo(); - size_t numWindows = windowHandles.size(); + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - sp otherHandle = windowHandles.itemAt(i); + sp otherHandle = mWindowHandles.itemAt(i); if (otherHandle == windowHandle) { break; } @@ -2915,77 +2909,52 @@ void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* ent } } -Vector> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const { - std::unordered_map>>::const_iterator it - = mWindowHandlesByDisplay.find(displayId); - if(it != mWindowHandlesByDisplay.end()) { - return it->second; - } - - // Return an empty one if nothing found. - return Vector>(); -} - sp InputDispatcher::getWindowHandleLocked( const sp& inputChannel) const { - for (auto& it : mWindowHandlesByDisplay) { - const Vector> windowHandles = it.second; - size_t numWindows = windowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - const sp& windowHandle = windowHandles.itemAt(i); - if (windowHandle->getInputChannel() == inputChannel) { - return windowHandle; - } + size_t numWindows = mWindowHandles.size(); + for (size_t i = 0; i < numWindows; i++) { + const sp& windowHandle = mWindowHandles.itemAt(i); + if (windowHandle->getInputChannel() == inputChannel) { + return windowHandle; } } return nullptr; } bool InputDispatcher::hasWindowHandleLocked( - const sp& windowHandle, int32_t displayId) const { - - const Vector> windowHandles = getWindowHandlesLocked(displayId); - size_t numWindows = windowHandles.size(); + const sp& windowHandle) const { + size_t numWindows = mWindowHandles.size(); for (size_t i = 0; i < numWindows; i++) { - if (windowHandles.itemAt(i) == windowHandle) { + if (mWindowHandles.itemAt(i) == windowHandle) { return true; } } return false; } -void InputDispatcher::setInputWindows(const Vector>& inputWindowHandles, - int displayId) { +void InputDispatcher::setInputWindows(const Vector >& inputWindowHandles) { #if DEBUG_FOCUS ALOGD("setInputWindows"); #endif { // acquire lock AutoMutex _l(mLock); - const Vector> oldWindowHandles = getWindowHandlesLocked(displayId); - Vector> windowHandles = inputWindowHandles; - // Insert or replace - mWindowHandlesByDisplay[displayId] = windowHandles; + Vector > oldWindowHandles = mWindowHandles; + mWindowHandles = inputWindowHandles; - // TODO(b/111361570): multi-display focus, one focus in all display in current. - sp newFocusedWindowHandle = mFocusedWindowHandle; + sp newFocusedWindowHandle; bool foundHoveredWindow = false; - - if (windowHandles.isEmpty()) { - // Remove all handles on a display if there are no windows left. - mWindowHandlesByDisplay.erase(displayId); - } else { - for (size_t i = 0; i < windowHandles.size(); i++) { - const sp& windowHandle = windowHandles.itemAt(i); - if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) { - continue; - } - if (windowHandle->getInfo()->hasFocus) { - newFocusedWindowHandle = windowHandle; - } - if (windowHandle == mLastHoverWindowHandle) { - foundHoveredWindow = true; - } + for (size_t i = 0; i < mWindowHandles.size(); i++) { + const sp& windowHandle = mWindowHandles.itemAt(i); + if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) { + mWindowHandles.removeAt(i--); + continue; + } + if (windowHandle->getInfo()->hasFocus) { + newFocusedWindowHandle = windowHandle; + } + if (windowHandle == mLastHoverWindowHandle) { + foundHoveredWindow = true; } } @@ -2993,7 +2962,6 @@ void InputDispatcher::setInputWindows(const Vector>& input mLastHoverWindowHandle = nullptr; } - // TODO(b/111361570): multi-display focus, one focus in all display in current. if (mFocusedWindowHandle != newFocusedWindowHandle) { if (mFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS @@ -3017,12 +2985,11 @@ void InputDispatcher::setInputWindows(const Vector>& input mFocusedWindowHandle = newFocusedWindowHandle; } - ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); - if (stateIndex >= 0) { - TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); + for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) { + TouchState& state = mTouchStatesByDisplay.editValueAt(d); for (size_t i = 0; i < state.windows.size(); ) { TouchedWindow& touchedWindow = state.windows.editItemAt(i); - if (!hasWindowHandleLocked(touchedWindow.windowHandle, displayId)) { + if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS ALOGD("Touched window was removed: %s", touchedWindow.windowHandle->getName().c_str()); @@ -3048,7 +3015,7 @@ void InputDispatcher::setInputWindows(const Vector>& input // which might not happen until the next GC. for (size_t i = 0; i < oldWindowHandles.size(); i++) { const sp& oldWindowHandle = oldWindowHandles.itemAt(i); - if (!hasWindowHandleLocked(oldWindowHandle, displayId)) { + if (!hasWindowHandleLocked(oldWindowHandle)) { #if DEBUG_FOCUS ALOGD("Window went away: %s", oldWindowHandle->getName().c_str()); #endif @@ -3299,44 +3266,36 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT "TouchStates: \n"; } - if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { - const Vector> windowHandles = it.second; - dump += StringPrintf(INDENT "Display: %d\n", it.first); - if (!windowHandles.isEmpty()) { - dump += INDENT "Windows:\n"; - for (size_t i = 0; i < windowHandles.size(); i++) { - const sp& windowHandle = windowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - - dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, " - "paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], scale=%f, " - "touchableRegion=", - i, windowInfo->name.c_str(), windowInfo->displayId, - toString(windowInfo->paused), - toString(windowInfo->hasFocus), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), - toString(windowInfo->canReceiveKeys), - windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, - windowInfo->layer, - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->scaleFactor); - dumpRegion(dump, windowInfo->touchableRegion); - dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures); - dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - windowInfo->ownerPid, windowInfo->ownerUid, - windowInfo->dispatchingTimeout / 1000000.0); - } - } else { - dump += INDENT "Windows: \n"; - } + if (!mWindowHandles.isEmpty()) { + dump += INDENT "Windows:\n"; + for (size_t i = 0; i < mWindowHandles.size(); i++) { + const sp& windowHandle = mWindowHandles.itemAt(i); + const InputWindowInfo* windowInfo = windowHandle->getInfo(); + + dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, " + "paused=%s, hasFocus=%s, hasWallpaper=%s, " + "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " + "frame=[%d,%d][%d,%d], scale=%f, " + "touchableRegion=", + i, windowInfo->name.c_str(), windowInfo->displayId, + toString(windowInfo->paused), + toString(windowInfo->hasFocus), + toString(windowInfo->hasWallpaper), + toString(windowInfo->visible), + toString(windowInfo->canReceiveKeys), + windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, + windowInfo->layer, + windowInfo->frameLeft, windowInfo->frameTop, + windowInfo->frameRight, windowInfo->frameBottom, + windowInfo->scaleFactor); + dumpRegion(dump, windowInfo->touchableRegion); + dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures); + dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", + windowInfo->ownerPid, windowInfo->ownerUid, + windowInfo->dispatchingTimeout / 1000000.0); } } else { - dump += INDENT "Displays: \n"; + dump += INDENT "Windows: \n"; } if (!mMonitoringChannels.isEmpty()) { diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 5cb7fe171e..31ab339421 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -31,7 +31,6 @@ #include #include #include -#include #include "InputWindow.h" #include "InputApplication.h" @@ -308,8 +307,7 @@ public: * * This method may be called on any thread (usually by the input manager). */ - virtual void setInputWindows(const Vector >& inputWindowHandles, - int displayId) = 0; + virtual void setInputWindows(const Vector >& inputWindowHandles) = 0; /* Sets the focused application. * @@ -389,8 +387,7 @@ public: int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags); - virtual void setInputWindows(const Vector >& inputWindowHandles, - int displayId); + virtual void setInputWindows(const Vector >& inputWindowHandles); virtual void setFocusedApplication(const sp& inputApplicationHandle); virtual void setInputDispatchMode(bool enabled, bool frozen); virtual void setInputFilterEnabled(bool enabled); @@ -959,11 +956,10 @@ private: bool mDispatchFrozen; bool mInputFilterEnabled; - std::unordered_map>> mWindowHandlesByDisplay; - // Get window handles by display, return an empty vector if not found. - Vector> getWindowHandlesLocked(int32_t displayId) const; + Vector > mWindowHandles; + sp getWindowHandleLocked(const sp& inputChannel) const; - bool hasWindowHandleLocked(const sp& windowHandle, int32_t displayId) const; + bool hasWindowHandleLocked(const sp& windowHandle) const; // Focus tracking for keys, trackball, etc. sp mFocusedWindowHandle; -- cgit v1.2.3-59-g8ed1b From 7f6d7b02b58844def96956d0c587692f38f2afeb Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Mon, 20 Aug 2018 19:53:42 +0000 Subject: Revert "Revert "Revert "SF: Updating permissions checking in Surface Flinger.""" This reverts commit fbe2c00188533f459c6c675f19c1953d48429d02. Reason for revert: Breaks Netflix/YouTube TV Bug: 112758347 Change-Id: Ia1eba75d3ea8fecec6855f2ab83c23e0b55b63d4 (cherry picked from commit e334440508f8e36729f04e80d963d84eebb5ad59) --- libs/gui/include/gui/ISurfaceComposer.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 109 +++---- services/surfaceflinger/tests/Android.bp | 1 - services/surfaceflinger/tests/Credentials_test.cpp | 322 --------------------- .../tests/SurfaceFlinger_test.filter | 2 +- 5 files changed, 46 insertions(+), 394 deletions(-) delete mode 100644 services/surfaceflinger/tests/Credentials_test.cpp diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 98ec33888d..e40157206d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -220,12 +220,12 @@ public: class BnSurfaceComposer: public BnInterface { public: - enum ISurfaceComposerTag { + enum { // Note: BOOT_FINISHED must remain this value, it is called from // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, - CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check + UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC CREATE_DISPLAY_EVENT_CONNECTION, CREATE_DISPLAY, DESTROY_DISPLAY, @@ -236,7 +236,7 @@ public: GET_DISPLAY_CONFIGS, GET_ACTIVE_CONFIG, SET_ACTIVE_CONFIG, - CONNECT_DISPLAY_UNUSED, // unused, fails permissions check + CONNECT_DISPLAY, CAPTURE_SCREEN, CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ae39202659..f5c0b7484b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1091,6 +1091,15 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) const NO_THREAD_SAFETY_ANALYSIS { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + // Try to acquire a lock for 1s, fail gracefully const status_t err = mStateLock.timedLock(s2ns(1)); const bool locked = (err == NO_ERROR); @@ -3249,8 +3258,9 @@ bool callingThreadHasUnscopedSurfaceFlingerAccess() { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && - !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { + !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { return false; } return true; @@ -4436,64 +4446,51 @@ void SurfaceFlinger::updateColorMatrixLocked() { } status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { -#pragma clang diagnostic push -#pragma clang diagnostic error "-Wswitch-enum" - switch (static_cast(code)) { - // These methods should at minimum make sure that the client requested - // access to SF. - case AUTHENTICATE_SURFACE: - case BOOT_FINISHED: - case CLEAR_ANIMATION_FRAME_STATS: + switch (code) { case CREATE_CONNECTION: case CREATE_DISPLAY: - case DESTROY_DISPLAY: - case ENABLE_VSYNC_INJECTIONS: - case GET_ACTIVE_COLOR_MODE: + case BOOT_FINISHED: + case CLEAR_ANIMATION_FRAME_STATS: case GET_ANIMATION_FRAME_STATS: + case SET_POWER_MODE: case GET_HDR_CAPABILITIES: - case SET_ACTIVE_CONFIG: - case SET_ACTIVE_COLOR_MODE: + case ENABLE_VSYNC_INJECTIONS: case INJECT_VSYNC: - case SET_POWER_MODE: { + { + // codes that require permission check if (!callingThreadHasUnscopedSurfaceFlingerAccess()) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(), ipc->getCallingUid()); return PERMISSION_DENIED; } + break; + } + /* + * Calling setTransactionState is safe, because you need to have been + * granted a reference to Client* and Handle* to do anything with it. + * + * Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h + */ + case SET_TRANSACTION_STATE: + case CREATE_SCOPED_CONNECTION: + { return OK; } - case GET_LAYER_DEBUG_INFO: { + case CAPTURE_SCREEN: + { + // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { - ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } - return OK; - } - // Used by apps to hook Choreographer to SurfaceFlinger. - case CREATE_DISPLAY_EVENT_CONNECTION: - // The following calls are currently used by clients that do not - // request necessary permissions. However, they do not expose any secret - // information, so it is OK to pass them. - case GET_ACTIVE_CONFIG: - case GET_BUILT_IN_DISPLAY: - case GET_DISPLAY_COLOR_MODES: - case GET_DISPLAY_CONFIGS: - case GET_DISPLAY_STATS: - case GET_SUPPORTED_FRAME_TIMESTAMPS: - // Calling setTransactionState is safe, because you need to have been - // granted a reference to Client* and Handle* to do anything with it. - case SET_TRANSACTION_STATE: - // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h - case CREATE_SCOPED_CONNECTION: { - return OK; + break; } - case CAPTURE_LAYERS: - case CAPTURE_SCREEN: { - // codes that require permission check + case CAPTURE_LAYERS: { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -4502,37 +4499,15 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; } - return OK; - } - // The following codes are deprecated and should never be allowed to access SF. - case CONNECT_DISPLAY_UNUSED: - case CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED: { - ALOGE("Attempting to access SurfaceFlinger with unused code: %u", code); - return PERMISSION_DENIED; + break; } } - - // These codes are used for the IBinder protocol to either interrogate the recipient - // side of the transaction for its canonical interface descriptor or to dump its state. - // We let them pass by default. - if (code == IBinder::INTERFACE_TRANSACTION || code == IBinder::DUMP_TRANSACTION || - code == IBinder::PING_TRANSACTION || code == IBinder::SHELL_COMMAND_TRANSACTION || - code == IBinder::SYSPROPS_TRANSACTION) { - return OK; - } - // Numbers from 1000 to 1029 are currently use for backdoors. The code - // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1029) { - ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); - return OK; - } - ALOGE("Permission Denial: SurfaceFlinger did not recognize request code: %u", code); - return PERMISSION_DENIED; -#pragma clang diagnostic pop + return OK; } -status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { +status_t SurfaceFlinger::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ status_t credentialCheck = CheckTransactCodeCredentials(code); if (credentialCheck != OK) { return credentialCheck; diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 604aa7df56..c511c5e753 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -17,7 +17,6 @@ cc_test { defaults: ["surfaceflinger_defaults"], test_suites: ["device-tests"], srcs: [ - "Credentials_test.cpp", "Stress_test.cpp", "SurfaceInterceptor_test.cpp", "Transaction_test.cpp", diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp deleted file mode 100644 index cd57411761..0000000000 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ /dev/null @@ -1,322 +0,0 @@ -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace android { - -using Transaction = SurfaceComposerClient::Transaction; - -namespace { -const String8 DISPLAY_NAME("Credentials Display Test"); -const String8 SURFACE_NAME("Test Surface Name"); -const int32_t MIN_LAYER_Z = 0; -const int32_t MAX_LAYER_Z = std::numeric_limits::max(); -const uint32_t ROTATION = 0; -const float FRAME_SCALE = 1.0f; -} // namespace - -/** - * This class tests the CheckCredentials method in SurfaceFlinger. - * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not - * return anything meaningful. - */ -class CredentialsTest : public ::testing::Test { -protected: - void SetUp() override { - // Start the tests as root. - seteuid(AID_ROOT); - - ASSERT_NO_FATAL_FAILURE(initClient()); - } - - void TearDown() override { - mComposerClient->dispose(); - mBGSurfaceControl.clear(); - mComposerClient.clear(); - // Finish the tests as root. - seteuid(AID_ROOT); - } - - sp mDisplay; - sp mVirtualDisplay; - sp mComposerClient; - sp mBGSurfaceControl; - sp mVirtualSurfaceControl; - - void initClient() { - mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - } - - void setupBackgroundSurface() { - mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); - DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(mDisplay, &info); - const ssize_t displayWidth = info.w; - const ssize_t displayHeight = info.h; - - // Background surface - mBGSurfaceControl = - mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(mBGSurfaceControl != nullptr); - ASSERT_TRUE(mBGSurfaceControl->isValid()); - - Transaction t; - t.setDisplayLayerStack(mDisplay, 0); - ASSERT_EQ(NO_ERROR, - t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply()); - } - - void setupVirtualDisplay() { - mVirtualDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); - const ssize_t displayWidth = 100; - const ssize_t displayHeight = 100; - - // Background surface - mVirtualSurfaceControl = - mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - ASSERT_TRUE(mVirtualSurfaceControl != nullptr); - ASSERT_TRUE(mVirtualSurfaceControl->isValid()); - - Transaction t; - t.setDisplayLayerStack(mVirtualDisplay, 0); - ASSERT_EQ(NO_ERROR, - t.setLayer(mVirtualSurfaceControl, INT_MAX - 3) - .show(mVirtualSurfaceControl) - .apply()); - } - - /** - * Sets UID to imitate Graphic's process. - */ - void setGraphicsUID() { - seteuid(AID_ROOT); - seteuid(AID_GRAPHICS); - } - - /** - * Sets UID to imitate System's process. - */ - void setSystemUID() { - seteuid(AID_ROOT); - seteuid(AID_SYSTEM); - } - - /** - * Sets UID to imitate a process that doesn't have any special privileges in - * our code. - */ - void setBinUID() { - seteuid(AID_ROOT); - seteuid(AID_BIN); - } - - /** - * Template function the check a condition for different types of users: root - * graphics, system, and non-supported user. Root, graphics, and system should - * always equal privilegedValue, and non-supported user should equal unprivilegedValue. - */ - template - void checkWithPrivileges(std::function condition, T privilegedValue, T unprivilegedValue) { - // Check with root. - seteuid(AID_ROOT); - ASSERT_EQ(privilegedValue, condition()); - - // Check as a Graphics user. - setGraphicsUID(); - ASSERT_EQ(privilegedValue, condition()); - - // Check as a system user. - setSystemUID(); - ASSERT_EQ(privilegedValue, condition()); - - // Check as a non-supported user. - setBinUID(); - ASSERT_EQ(unprivilegedValue, condition()); - } -}; - -TEST_F(CredentialsTest, ClientInitTest) { - // Root can init can init the client. - ASSERT_NO_FATAL_FAILURE(initClient()); - - // Graphics can init the client. - setGraphicsUID(); - ASSERT_NO_FATAL_FAILURE(initClient()); - - // System can init the client. - setSystemUID(); - ASSERT_NO_FATAL_FAILURE(initClient()); - - // No one else can init the client. - setBinUID(); - mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_INIT, mComposerClient->initCheck()); -} - -TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) { - std::function condition = [=]() { - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - return (display != nullptr); - }; - // Anyone can access display information. - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); -} - -TEST_F(CredentialsTest, AllowedGetterMethodsTest) { - // The following methods are tested with a UID that is not root, graphics, - // or system, to show that anyone can access them. - setBinUID(); - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - ASSERT_TRUE(display != nullptr); - - DisplayInfo info; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info)); - - Vector configs; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs)); - - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display)); - - ASSERT_NE(static_cast(BAD_VALUE), - SurfaceComposerClient::getActiveColorMode(display)); -} - -TEST_F(CredentialsTest, GetDisplayColorModesTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - Vector outColorModes; - return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); -} - -TEST_F(CredentialsTest, SetActiveConfigTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - return SurfaceComposerClient::setActiveConfig(display, 0); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -TEST_F(CredentialsTest, SetActiveColorModeTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -TEST_F(CredentialsTest, CreateSurfaceTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); - const ssize_t displayWidth = info.w; - const ssize_t displayHeight = info.h; - - std::function condition = [=]() { - mBGSurfaceControl = - mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - return mBGSurfaceControl != nullptr && mBGSurfaceControl->isValid(); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); -} - -TEST_F(CredentialsTest, CreateDisplayTest) { - std::function condition = [=]() { - sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); - return testDisplay.get() != nullptr; - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); - - condition = [=]() { - sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false); - return testDisplay.get() != nullptr; - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); -} - -TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) { - setupVirtualDisplay(); - - DisplayInfo info; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info)); - SurfaceComposerClient::destroyDisplay(mVirtualDisplay); - // This test currently fails. TODO(b/112002626): Find a way to properly create - // a display in the test environment, so that destroy display can remove it. - ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info)); -} - -TEST_F(CredentialsTest, CaptureTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - std::function condition = [=]() { - sp outBuffer; - return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, - MIN_LAYER_Z, MAX_LAYER_Z, false, ROTATION, &outBuffer); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -TEST_F(CredentialsTest, CaptureLayersTest) { - setupBackgroundSurface(); - sp outBuffer; - std::function condition = [=]() { - sp outBuffer; - return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE, - &outBuffer); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - -/** - * Test for methods accessible directly through SurfaceFlinger: - */ -TEST_F(CredentialsTest, AuthenticateSurfaceTextureTest) { - setupBackgroundSurface(); - sp producer = - mBGSurfaceControl->getSurface()->getIGraphicBufferProducer(); - sp sf(ComposerService::getComposerService()); - - std::function condition = [=]() { return sf->authenticateSurfaceTexture(producer); }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); -} - -TEST_F(CredentialsTest, GetLayerDebugInfo) { - setupBackgroundSurface(); - sp sf(ComposerService::getComposerService()); - - // Historically, only root and shell can access the getLayerDebugInfo which - // is called when we call dumpsys. I don't see a reason why we should change this. - std::vector outLayers; - // Check with root. - seteuid(AID_ROOT); - ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); - - // Check as a shell. - seteuid(AID_SHELL); - ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); - - // Check as anyone else. - seteuid(AID_ROOT); - seteuid(AID_BIN); - ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers)); -} -} // namespace android diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter index 1319e12493..731e628bb8 100644 --- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter +++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter @@ -1,5 +1,5 @@ { "presubmit": { - "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize" + "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize" } } -- cgit v1.2.3-59-g8ed1b From 67b4aff94227bcd0abf584333320695abf177422 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Mon, 17 Sep 2018 17:44:38 -0700 Subject: OtaDexopt: Temporarily disable Exit-early from the OTA script to avoid a bug. We need to skip an OTA as the code in question runs in the host part. It is easier to early-return than to remove to postinstall hook, as that is registered on a per-product basis. Bug: 115853663 Test: m Change-Id: I8ebcdd7d800c5c4d27a0f07fb4145b88fd19791e (cherry picked from commit c0ba0e4b0882a2454f162c453099d4371fc66b15) --- cmds/installd/otapreopt_script.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh index f950276090..0c586b6ce0 100644 --- a/cmds/installd/otapreopt_script.sh +++ b/cmds/installd/otapreopt_script.sh @@ -18,6 +18,9 @@ # This script will run as a postinstall step to drive otapreopt. +# Temporarily disable for b/115853663. +exit 0 + TARGET_SLOT="$1" STATUS_FD="$2" -- cgit v1.2.3-59-g8ed1b From 4fad558acdb5f96cf03d1518242ad4146f55e7ea Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Mon, 17 Sep 2018 17:44:38 -0700 Subject: OtaDexopt: Temporarily disable Exit-early from the OTA script to avoid a bug. We need to skip an OTA as the code in question runs in the host part. It is easier to early-return than to remove to postinstall hook, as that is registered on a per-product basis. Bug: 115853663 Test: m Change-Id: I8ebcdd7d800c5c4d27a0f07fb4145b88fd19791e (cherry picked from commit c0ba0e4b0882a2454f162c453099d4371fc66b15) --- cmds/installd/otapreopt_script.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh index f950276090..0c586b6ce0 100644 --- a/cmds/installd/otapreopt_script.sh +++ b/cmds/installd/otapreopt_script.sh @@ -18,6 +18,9 @@ # This script will run as a postinstall step to drive otapreopt. +# Temporarily disable for b/115853663. +exit 0 + TARGET_SLOT="$1" STATUS_FD="$2" -- cgit v1.2.3-59-g8ed1b From 7dd4382c45eb3960debfd2b064f907288662d2fa Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Fri, 12 Oct 2018 14:34:26 -0600 Subject: Revert "Rootless Debug for GLES" This reverts commit d9f0ec416aa89d8213effa8b983de974b2c667bd. Bug: 110883880 Test: Chrome no longer crashes Change-Id: I57d08a33a392394bd0a2cf4d7af97a3cce7ed8f5 (cherry picked from commit 9f20d92fb3b7ed2a88d2e497ec36d21e9005f497) --- libs/graphicsenv/Android.bp | 1 - libs/graphicsenv/GraphicsEnv.cpp | 17 - libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 14 +- opengl/libs/Android.bp | 4 - opengl/libs/EGL/egl.cpp | 11 +- opengl/libs/EGL/egl_layers.cpp | 433 --------------------- opengl/libs/EGL/egl_layers.h | 65 ---- opengl/libs/EGL/egl_platform_entries.cpp | 92 ++--- 8 files changed, 43 insertions(+), 594 deletions(-) delete mode 100644 opengl/libs/EGL/egl_layers.cpp delete mode 100644 opengl/libs/EGL/egl_layers.h diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index bab87acb05..4da30e9980 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -23,7 +23,6 @@ cc_library_shared { shared_libs: [ "liblog", - "libcutils", ], export_include_dirs: ["include"], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 3328ad7291..2a7d76e856 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -18,12 +18,9 @@ #define LOG_TAG "GraphicsEnv" #include -#include - #include #include -#include #include // TODO(b/37049319) Get this from a header once one exists @@ -49,14 +46,6 @@ namespace android { return env; } -int GraphicsEnv::getCanLoadSystemLibraries() { - if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { - // Return an integer value since this crosses library boundaries - return 1; - } - return 0; -} - void GraphicsEnv::setDriverPath(const std::string path) { if (!mDriverPath.empty()) { ALOGV("ignoring attempt to change driver path from '%s' to '%s'", @@ -192,10 +181,4 @@ bool android_getAngleDeveloperOptIn() { const char* android_getAngleAppPref() { return android::GraphicsEnv::getInstance().getAngleAppPref(); } -const char* android_getLayerPaths() { - return android::GraphicsEnv::getInstance().getLayerPaths().c_str(); -} -const char* android_getDebugLayers() { - return android::GraphicsEnv::getInstance().getDebugLayers().c_str(); -} } diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 1783429b9d..00e8fc01f7 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -29,8 +29,6 @@ class GraphicsEnv { public: static GraphicsEnv& getInstance(); - int getCanLoadSystemLibraries(); - // Set a search path for loading graphics drivers. The path is a list of // directories separated by ':'. A directory can be contained in a zip file // (drivers must be stored uncompressed and page aligned); such elements @@ -87,13 +85,11 @@ private: * will be removed soon. */ extern "C" { - android_namespace_t* android_getDriverNamespace(); - android_namespace_t* android_getAngleNamespace(); - const char* android_getAngleAppName(); - const char* android_getAngleAppPref(); - bool android_getAngleDeveloperOptIn(); - const char* android_getLayerPaths(); - const char* android_getDebugLayers(); +android_namespace_t* android_getDriverNamespace(); +android_namespace_t* android_getAngleNamespace(); +const char* android_getAngleAppName(); +const char* android_getAngleAppPref(); +bool android_getAngleDeveloperOptIn(); } #endif // ANDROID_UI_GRAPHICS_ENV_H diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 583aec9db5..fb6a221973 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -140,7 +140,6 @@ cc_library_shared { "EGL/egl_cache.cpp", "EGL/egl_display.cpp", "EGL/egl_object.cpp", - "EGL/egl_layers.cpp", "EGL/egl.cpp", "EGL/eglApi.cpp", "EGL/egl_platform_entries.cpp", @@ -151,11 +150,8 @@ cc_library_shared { "libvndksupport", "android.hardware.configstore@1.0", "android.hardware.configstore-utils", - "libbase", "libhidlbase", "libhidltransport", - "libnativebridge", - "libnativeloader", "libutils", ], static_libs: [ diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 01795e0af3..d0cfadaff1 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -30,10 +30,11 @@ #include "egl_tls.h" #include "egl_display.h" #include "egl_object.h" -#include "egl_layers.h" #include "CallStack.h" #include "Loader.h" +typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer; + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- @@ -195,14 +196,6 @@ static EGLBoolean egl_init_drivers_locked() { cnx->dso = loader.open(cnx); } - // Check to see if any layers are enabled and route functions through them - if (cnx->dso) { - // Layers can be enabled long after the drivers have been loaded. - // They will only be initialized once. - LayerLoader& layer_loader(LayerLoader::getInstance()); - layer_loader.InitLayers(cnx); - } - return cnx->dso ? EGL_TRUE : EGL_FALSE; } diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp deleted file mode 100644 index 6900b8b464..0000000000 --- a/opengl/libs/EGL/egl_layers.cpp +++ /dev/null @@ -1,433 +0,0 @@ -/* - ** Copyright 2018, 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. - */ - -#include "egl_layers.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -// GLES Layers -// -// - Layer discovery - -// 1. Check for debug layer list from GraphicsEnv -// 2. If none enabled, check system properties -// -// - Layer initializing - -// TODO: ADD DETAIL ABOUT NEW INTERFACES -// - InitializeLayer (provided by layer, called by loader) -// - GetLayerProcAddress (provided by layer, called by loader) -// - getNextLayerProcAddress (provided by loader, called by layer) -// -// 1. Walk through defs for egl and each gl version -// 2. Call GetLayerProcAddress passing the name and the target hook entry point -// - This tells the layer the next point in the chain it should call -// 3. Replace the hook with the layer's entry point -// - All entryoints will be present, anything unsupported by the driver will -// have gl_unimplemented -// -// - Extension layering - -// Not all functions are known to Android, so libEGL handles extensions. -// They are looked up by applications using eglGetProcAddress -// Layers can look them up with getNextLayerProcAddress - -const int kFuncCount = sizeof(platform_impl_t) / sizeof(char*) + sizeof(egl_t) / sizeof(char*) + - sizeof(gl_hooks_t) / sizeof(char*); - -typedef struct FunctionTable { - EGLFuncPointer x[kFuncCount]; - EGLFuncPointer& operator[](int i) { return x[i]; } -} FunctionTable; - -// TODO: Move these to class -std::unordered_map func_indices; -// func_indices.reserve(kFuncCount); - -std::unordered_map func_names; -// func_names.reserve(kFuncCount); - -std::vector layer_functions; - -const void* getNextLayerProcAddress(void* layer_id, const char* name) { - // Use layer_id to find funcs for layer below current - // This is the same key provided in InitializeLayer - auto next_layer_funcs = reinterpret_cast(layer_id); - EGLFuncPointer val; - - if (func_indices.find(name) == func_indices.end()) { - // No entry for this function - it is an extension - // call down the GPA chain directly to the impl - ALOGV("getNextLayerProcAddress servicing %s", name); - - // Look up which GPA we should use - int gpaIndex = func_indices["eglGetProcAddress"]; - EGLFuncPointer gpaNext = (*next_layer_funcs)[gpaIndex]; - - ALOGV("Calling down the GPA chain (%llu) for %s", (unsigned long long)gpaNext, name); - - // Call it for the requested function - typedef void* (*PFNEGLGETPROCADDRESSPROC)(const char*); - PFNEGLGETPROCADDRESSPROC next = reinterpret_cast(gpaNext); - - val = reinterpret_cast(next(name)); - ALOGV("Got back %llu for %s", (unsigned long long)val, name); - - // We should store it now, but to do that, we need to move func_idx to the class so we can - // increment it separately - // TODO: Move func_idx to class and store the result of GPA - return reinterpret_cast(val); - } - - // int index = func_indices[name]; - // val = (*next_layer_funcs)[index]; - // return reinterpret_cast(val); - return reinterpret_cast((*next_layer_funcs)[func_indices[name]]); -} - -void SetupFuncMaps(FunctionTable& functions, char const* const* entries, EGLFuncPointer* curr, - int& func_idx) { - while (*entries) { - const char* name = *entries; - - // Some names overlap, only fill with initial entry - // This does mean that some indices will not be used - if (func_indices.find(name) == func_indices.end()) { - func_names[func_idx] = name; - func_indices[name] = func_idx; - } - - // Populate layer_functions once with initial value - // These values will arrive in priority order, starting with platform entries - if (functions[func_idx] == nullptr) { - functions[func_idx] = *curr; - } - - entries++; - curr++; - func_idx++; - } -} - -LayerLoader& LayerLoader::getInstance() { - // This function is mutex protected in egl_init_drivers_locked and eglGetProcAddressImpl - static LayerLoader layer_loader; - - if (!layer_loader.layers_loaded_) layer_loader.LoadLayers(); - - return layer_loader; -} - -const char kSystemLayerLibraryDir[] = "/data/local/debug/gles"; - -std::string LayerLoader::GetDebugLayers() { - // Layers can be specified at the Java level in GraphicsEnvironemnt - // gpu_debug_layers = layer1:layer2:layerN - std::string debug_layers = android_getDebugLayers(); - - if (debug_layers.empty()) { - // Only check system properties if Java settings are empty - char prop[PROPERTY_VALUE_MAX]; - property_get("debug.gles.layers", prop, ""); - debug_layers = prop; - } - - return debug_layers; -} - -EGLFuncPointer LayerLoader::ApplyLayer(layer_setup_func layer_setup, const char* name, - EGLFuncPointer next) { - // Walk through our list of LayerSetup functions (they will already be in reverse order) to - // build up a call chain from the driver - - EGLFuncPointer layer_entry = next; - - layer_entry = layer_setup(name, layer_entry); - - if (next != layer_entry) { - ALOGV("We succeeded, replacing hook (%llu) with layer entry (%llu), for %s", - (unsigned long long)next, (unsigned long long)layer_entry, name); - } - - return layer_entry; -} - -EGLFuncPointer LayerLoader::ApplyLayers(const char* name, EGLFuncPointer next) { - if (!layers_loaded_ || layer_setup_.empty()) return next; - - ALOGV("ApplyLayers called for %s with next (%llu), current_layer_ (%i)", name, - (unsigned long long)next, current_layer_); - - EGLFuncPointer val = next; - - // Only ApplyLayers for layers that have been setup, not all layers yet - for (unsigned i = 0; i < current_layer_; i++) { - ALOGV("ApplyLayers: Calling ApplyLayer with i = %i for %s with next (%llu)", i, name, - (unsigned long long)next); - val = ApplyLayer(layer_setup_[i], name, val); - } - - ALOGV("ApplyLayers returning %llu for %s", (unsigned long long)val, name); - - return val; -} - -void LayerLoader::LayerPlatformEntries(layer_setup_func layer_setup, EGLFuncPointer* curr, - char const* const* entries) { - while (*entries) { - char const* name = *entries; - - EGLFuncPointer prev = *curr; - - // Pass the existing entry point into the layer, replace the call with return value - *curr = ApplyLayer(layer_setup, name, *curr); - - if (prev != *curr) { - ALOGV("LayerPlatformEntries: Replaced (%llu) with platform entry (%llu), for %s", - (unsigned long long)prev, (unsigned long long)*curr, name); - } else { - ALOGV("LayerPlatformEntries: No change(%llu) for %s, which means layer did not " - "intercept", - (unsigned long long)prev, name); - } - - curr++; - entries++; - } -} - -void LayerLoader::LayerDriverEntries(layer_setup_func layer_setup, EGLFuncPointer* curr, - char const* const* entries) { - while (*entries) { - char const* name = *entries; - EGLFuncPointer prev = *curr; - - // Only apply layers to driver entries if not handled by the platform - if (FindPlatformImplAddr(name) == nullptr) { - // Pass the existing entry point into the layer, replace the call with return value - *curr = ApplyLayer(layer_setup, name, *prev); - - if (prev != *curr) { - ALOGV("LayerDriverEntries: Replaced (%llu) with platform entry (%llu), for %s", - (unsigned long long)prev, (unsigned long long)*curr, name); - } - - } else { - ALOGV("LayerDriverEntries: Skipped (%llu) for %s", (unsigned long long)prev, name); - } - - curr++; - entries++; - } -} - -bool LayerLoader::Initialized() { - return initialized_; -} - -void LayerLoader::InitLayers(egl_connection_t* cnx) { - if (!layers_loaded_) return; - - if (initialized_) return; - - if (layer_setup_.empty()) { - initialized_ = true; - return; - } - - // Include the driver in layer_functions - layer_functions.resize(layer_setup_.size() + 1); - - // Walk through the initial lists and create layer_functions[0] - int func_idx = 0; - char const* const* entries; - EGLFuncPointer* curr; - - entries = platform_names; - curr = reinterpret_cast(&cnx->platform); - SetupFuncMaps(layer_functions[0], entries, curr, func_idx); - ALOGV("InitLayers: func_idx after platform_names: %i", func_idx); - - entries = egl_names; - curr = reinterpret_cast(&cnx->egl); - SetupFuncMaps(layer_functions[0], entries, curr, func_idx); - ALOGV("InitLayers: func_idx after egl_names: %i", func_idx); - - entries = gl_names; - curr = reinterpret_cast(&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl); - SetupFuncMaps(layer_functions[0], entries, curr, func_idx); - ALOGV("InitLayers: func_idx after gl_names: %i", func_idx); - - // Walk through each layer's entry points per API, starting just above the driver - for (current_layer_ = 0; current_layer_ < layer_setup_.size(); current_layer_++) { - // Init the layer with a key that points to layer just below it - layer_init_[current_layer_](reinterpret_cast(&layer_functions[current_layer_]), - reinterpret_cast( - getNextLayerProcAddress)); - - // Check functions implemented by the platform - func_idx = 0; - entries = platform_names; - curr = reinterpret_cast(&cnx->platform); - LayerPlatformEntries(layer_setup_[current_layer_], curr, entries); - - // Populate next function table after layers have been applied - SetupFuncMaps(layer_functions[current_layer_ + 1], entries, curr, func_idx); - - // EGL - entries = egl_names; - curr = reinterpret_cast(&cnx->egl); - LayerDriverEntries(layer_setup_[current_layer_], curr, entries); - - // Populate next function table after layers have been applied - SetupFuncMaps(layer_functions[current_layer_ + 1], entries, curr, func_idx); - - // GLES 2+ - // NOTE: We route calls to GLESv2 hooks, not GLESv1, so layering does not support GLES 1.x - // If it were added in the future, a different layer initialization model would be needed, - // that defers loading GLES entrypoints until after eglMakeCurrent, so two phase - // initialization. - entries = gl_names; - curr = reinterpret_cast(&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl); - LayerDriverEntries(layer_setup_[current_layer_], curr, entries); - - // Populate next function table after layers have been applied - SetupFuncMaps(layer_functions[current_layer_ + 1], entries, curr, func_idx); - } - - // We only want to apply layers once - initialized_ = true; -} - -void LayerLoader::LoadLayers() { - std::string debug_layers = GetDebugLayers(); - - // If no layers are specified, we're done - if (debug_layers.empty()) return; - - // Only enable the system search path for non-user builds - std::string system_path; - if (property_get_bool("ro.debuggable", false) && prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { - system_path = kSystemLayerLibraryDir; - } - - ALOGI("Debug layer list: %s", debug_layers.c_str()); - std::vector layers = android::base::Split(debug_layers, ":"); - - // Load the layers in reverse order so we start with the driver's entrypoint and work our way up - for (int32_t i = layers.size() - 1; i >= 0; i--) { - // Check each layer path for the layer - std::vector paths = android::base::Split(android_getLayerPaths(), ":"); - - if (!system_path.empty()) { - // Prepend the system paths so they override other layers - auto it = paths.begin(); - paths.insert(it, system_path); - } - - bool layer_found = false; - for (uint32_t j = 0; j < paths.size() && !layer_found; j++) { - std::string layer; - - ALOGI("Searching %s for GLES layers", paths[j].c_str()); - - // Realpath will return null for non-existent files - android::base::Realpath(paths[j] + "/" + layers[i], &layer); - - if (!layer.empty()) { - layer_found = true; - ALOGI("GLES layer found: %s", layer.c_str()); - - // Load the layer - // - // TODO: This code is common with Vulkan loader, refactor - // - // Libraries in the system layer library dir can't be loaded into - // the application namespace. That causes compatibility problems, since - // any symbol dependencies will be resolved by system libraries. They - // can't safely use libc++_shared, for example. Which is one reason - // (among several) we only allow them in non-user builds. - void* handle = nullptr; - auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace(); - if (app_namespace && !android::base::StartsWith(layer, kSystemLayerLibraryDir)) { - bool native_bridge = false; - std::string error_message; - handle = OpenNativeLibrary(app_namespace, layer.c_str(), &native_bridge, - &error_message); - if (!handle) { - ALOGE("Failed to load layer %s with error: %s", layer.c_str(), - error_message.c_str()); - return; - } - - } else { - handle = dlopen(layer.c_str(), RTLD_NOW | RTLD_LOCAL); - } - - if (handle) { - ALOGV("Loaded layer handle (%llu) for layer %s", (unsigned long long)handle, - layers[i].c_str()); - } else { - // If the layer is found but can't be loaded, try setenforce 0 - const char* dlsym_error = dlerror(); - ALOGE("Failed to load layer %s with error: %s", layer.c_str(), dlsym_error); - return; - } - - // Find the layer's Initialize function - std::string init_func = "InitializeLayer"; - ALOGV("Looking for entrypoint %s", init_func.c_str()); - - layer_init_func LayerInit = - reinterpret_cast(dlsym(handle, init_func.c_str())); - if (LayerInit) { - ALOGV("Found %s for layer %s", init_func.c_str(), layer.c_str()); - layer_init_.push_back(LayerInit); - } else { - ALOGE("Failed to dlsym %s for layer %s", init_func.c_str(), layer.c_str()); - return; - } - - // Find the layer's setup function - std::string setup_func = "GetLayerProcAddress"; - ALOGV("Looking for entrypoint %s", setup_func.c_str()); - - layer_setup_func LayerSetup = - reinterpret_cast(dlsym(handle, setup_func.c_str())); - if (LayerSetup) { - ALOGV("Found %s for layer %s", setup_func.c_str(), layer.c_str()); - layer_setup_.push_back(LayerSetup); - } else { - ALOGE("Failed to dlsym %s for layer %s", setup_func.c_str(), layer.c_str()); - return; - } - } - } - } - // Track this so we only attempt to load these once - layers_loaded_ = true; -} - -} // namespace android diff --git a/opengl/libs/EGL/egl_layers.h b/opengl/libs/EGL/egl_layers.h deleted file mode 100644 index e401b448cf..0000000000 --- a/opengl/libs/EGL/egl_layers.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#ifndef ANDROID_EGL_LAYERS_H -#define ANDROID_EGL_LAYERS_H - -#include -#include -#include - -#include - -#include "egl_platform_entries.h" - -typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer; - -namespace android { - -class LayerLoader { -public: - static LayerLoader& getInstance(); - ~LayerLoader(){}; - - typedef void* (*PFNEGLGETNEXTLAYERPROCADDRESSPROC)(void*, const char*); - typedef EGLFuncPointer (*layer_init_func)( - const void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address); - typedef EGLFuncPointer (*layer_setup_func)(const char* name, EGLFuncPointer next); - - void LoadLayers(); - void InitLayers(egl_connection_t*); - void LayerPlatformEntries(layer_setup_func layer_setup, EGLFuncPointer*, char const* const*); - void LayerDriverEntries(layer_setup_func layer_setup, EGLFuncPointer*, char const* const*); - bool Initialized(); - std::string GetDebugLayers(); - - EGLFuncPointer GetGpaNext(unsigned i); - EGLFuncPointer ApplyLayer(layer_setup_func layer_setup, const char* name, EGLFuncPointer next); - EGLFuncPointer ApplyLayers(const char* name, EGLFuncPointer next); - - std::vector layer_init_; - std::vector layer_setup_; - -private: - LayerLoader() : layers_loaded_(false), initialized_(false), current_layer_(0){}; - bool layers_loaded_; - bool initialized_; - unsigned current_layer_; -}; - -}; // namespace android - -#endif // ANDROID_EGL_LAYERS_H diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 0d69a658e3..296ee44ce5 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -30,8 +30,6 @@ #include #include -#include -#include #include #include @@ -49,7 +47,6 @@ #include "egl_display.h" #include "egl_object.h" -#include "egl_layers.h" #include "egl_tls.h" #include "egl_trace.h" @@ -1161,71 +1158,54 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn // this protects accesses to sGLExtentionMap and sGLExtentionSlot pthread_mutex_lock(&sExtensionMapMutex); - /* - * Since eglGetProcAddress() is not associated to anything, it needs - * to return a function pointer that "works" regardless of what - * the current context is. - * - * For this reason, we return a "forwarder", a small stub that takes - * care of calling the function associated with the context - * currently bound. - * - * We first look for extensions we've already resolved, if we're seeing - * this extension for the first time, we go through all our - * implementations and call eglGetProcAddress() and record the - * result in the appropriate implementation hooks and return the - * address of the forwarder corresponding to that hook set. - * - */ - - const std::string name(procname); + /* + * Since eglGetProcAddress() is not associated to anything, it needs + * to return a function pointer that "works" regardless of what + * the current context is. + * + * For this reason, we return a "forwarder", a small stub that takes + * care of calling the function associated with the context + * currently bound. + * + * We first look for extensions we've already resolved, if we're seeing + * this extension for the first time, we go through all our + * implementations and call eglGetProcAddress() and record the + * result in the appropriate implementation hooks and return the + * address of the forwarder corresponding to that hook set. + * + */ + + const std::string name(procname); auto& extentionMap = sGLExtentionMap; auto pos = extentionMap.find(name); - addr = (pos != extentionMap.end()) ? pos->second : nullptr; - const int slot = sGLExtentionSlot; + addr = (pos != extentionMap.end()) ? pos->second : nullptr; + const int slot = sGLExtentionSlot; - ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, - "no more slots for eglGetProcAddress(\"%s\")", - procname); + ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, + "no more slots for eglGetProcAddress(\"%s\")", + procname); - egl_connection_t* const cnx = &gEGLImpl; - LayerLoader& layer_loader(LayerLoader::getInstance()); - - if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { - - if (cnx->dso && cnx->egl.eglGetProcAddress) { - - // Extensions are independent of the bound context - addr = cnx->egl.eglGetProcAddress(procname); - if (addr) { - - // purposefully track the bottom of the stack in extensionMap - extentionMap[name] = addr; - - // Apply layers - addr = layer_loader.ApplyLayers(procname, addr); + if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { + bool found = false; - // Track the top most entry point + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetProcAddress) { + // Extensions are independent of the bound context + addr = cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = - cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr; + cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = + cnx->egl.eglGetProcAddress(procname); + if (addr) found = true; + } + + if (found) { addr = gExtensionForwarders[slot]; + extentionMap[name] = addr; sGLExtentionSlot++; } } - } else if (slot < MAX_NUMBER_OF_GL_EXTENSIONS) { - - // We've seen this func before, but we tracked the bottom, so re-apply layers - // More layers might have been enabled - addr = layer_loader.ApplyLayers(procname, addr); - - // Track the top most entry point - cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = - cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr; - addr = gExtensionForwarders[slot]; - } - pthread_mutex_unlock(&sExtensionMapMutex); return addr; } -- cgit v1.2.3-59-g8ed1b From f908b0355fac1dcbb31b3df0faf962e41e099b6d Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Fri, 12 Oct 2018 14:34:42 -0600 Subject: Revert "Split platform functions from entrypoints" This reverts commit 87a562ced75efb1383a553bf8837ec3b9b848920. Bug: 110883880 Test: Chrome no longer crashes Change-Id: I81d97298cbfd7f947920b6e9e8ad3abcd1a0d75a (cherry picked from commit d18d55344f9c1133c6b4f41aa6defcde1c32c7f3) --- opengl/libs/Android.bp | 1 - opengl/libs/EGL/Loader.cpp | 24 +- opengl/libs/EGL/Loader.h | 3 +- opengl/libs/EGL/egl.cpp | 9 - opengl/libs/EGL/eglApi.cpp | 585 ------------------------------- opengl/libs/EGL/egl_platform_entries.cpp | 522 ++++++++++++++------------- opengl/libs/EGL/egl_platform_entries.h | 31 -- opengl/libs/EGL/egldefs.h | 5 - opengl/libs/GLES2/gl2.cpp | 64 +++- opengl/libs/egl_impl.h | 3 - opengl/libs/hooks.h | 4 - opengl/libs/platform_entries.in | 76 ---- 12 files changed, 311 insertions(+), 1016 deletions(-) delete mode 100644 opengl/libs/EGL/eglApi.cpp delete mode 100644 opengl/libs/EGL/egl_platform_entries.h delete mode 100644 opengl/libs/platform_entries.in diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index fb6a221973..78309d419f 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,7 +141,6 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", - "EGL/eglApi.cpp", "EGL/egl_platform_entries.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 5aa03a7647..018d97977a 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -33,7 +33,6 @@ #endif #include -#include "egl_platform_entries.h" #include "egl_trace.h" #include "egldefs.h" @@ -238,12 +237,12 @@ void* Loader::open(egl_connection_t* cnx) setEmulatorGlesValue(); - dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2 | PLATFORM); + dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2); if (dso) { hnd = new driver_t(dso); } else { // Always load EGL first - dso = load_driver("EGL", cnx, EGL | PLATFORM); + dso = load_driver("EGL", cnx, EGL); if (dso) { hnd = new driver_t(dso); hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM ); @@ -624,25 +623,6 @@ void *Loader::load_driver(const char* kind, return nullptr; } - if (mask & PLATFORM) { - // For each entrypoint tracked by the platform - char const* const* entries = platform_names; - EGLFuncPointer* curr = reinterpret_cast(&cnx->platform); - - while (*entries) { - const char* name = *entries; - EGLFuncPointer f = FindPlatformImplAddr(name); - - if (f == nullptr) { - // If no entry found, update the lookup table: sPlatformImplMap - ALOGE("No entry found in platform lookup table for %s", name); - } - - *curr++ = f; - entries++; - } - } - if (mask & EGL) { getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress"); diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 93c33a824b..6a32bb3066 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -33,8 +33,7 @@ class Loader { enum { EGL = 0x01, GLESv1_CM = 0x02, - GLESv2 = 0x04, - PLATFORM = 0x08 + GLESv2 = 0x04 }; struct driver_t { explicit driver_t(void* gles); diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index d0cfadaff1..e292b80ac5 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -167,10 +167,6 @@ GLint egl_get_num_extensions_for_current_context() { return (GLint)c->tokenized_gl_extensions.size(); } -egl_connection_t* egl_get_connection() { - return &gEGLImpl; -} - // ---------------------------------------------------------------------------- // this mutex protects: @@ -261,11 +257,6 @@ char const * const egl_names[] = { nullptr }; -char const * const platform_names[] = { - #include "platform_entries.in" - nullptr -}; - #undef GL_ENTRY #undef EGL_ENTRY diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp deleted file mode 100644 index 8202c4eaae..0000000000 --- a/opengl/libs/EGL/eglApi.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/* - ** Copyright 2018, 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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include -#include - -#include "../egl_impl.h" - -#include "egl_layers.h" -#include "egl_platform_entries.h" -#include "egl_tls.h" -#include "egl_trace.h" - -using namespace android; - -namespace android { - -extern EGLBoolean egl_init_drivers(); - -} // namespace android - -static inline void clearError() { - egl_tls_t::clearError(); -} - -EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { - ATRACE_CALL(); - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); - } - - // Call down the chain, which usually points directly to the impl - // but may also be routed through layers - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetDisplay(display); -} - -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglInitialize(dpy, major, minor); -} - -EGLBoolean eglTerminate(EGLDisplay dpy) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglTerminate(dpy); -} - -EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, - EGLint* num_config) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetConfigs(dpy, configs, config_size, num_config); -} - -EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, - EGLint config_size, EGLint* num_config) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglChooseConfig(dpy, attrib_list, configs, config_size, num_config); -} - -EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetConfigAttrib(dpy, config, attribute, value); -} - -EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window, - const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateWindowSurface(dpy, config, window, attrib_list); -} - -EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, - const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreatePixmapSurface(dpy, config, pixmap, attrib_list); -} - -EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreatePbufferSurface(dpy, config, attrib_list); -} - -EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroySurface(dpy, surface); -} - -EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQuerySurface(dpy, surface, attribute, value); -} - -void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { - ATRACE_CALL(); - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - cnx->platform.eglBeginFrame(dpy, surface); -} - -EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list, - const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateContext(dpy, config, share_list, attrib_list); -} - -EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroyContext(dpy, ctx); -} - -EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglMakeCurrent(dpy, draw, read, ctx); -} - -EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryContext(dpy, ctx, attribute, value); -} - -EGLContext eglGetCurrentContext(void) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetCurrentContext(); -} - -EGLSurface eglGetCurrentSurface(EGLint readdraw) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetCurrentSurface(readdraw); -} - -EGLDisplay eglGetCurrentDisplay(void) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetCurrentDisplay(); -} - -EGLBoolean eglWaitGL(void) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglWaitGL(); -} - -EGLBoolean eglWaitNative(EGLint engine) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglWaitNative(engine); -} - -EGLint eglGetError(void) { - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->platform.eglGetError) { - return cnx->platform.eglGetError(); - } else { - return egl_tls_t::getError(); - } -} - -__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char* procname) { - // eglGetProcAddress() could be the very first function called - // in which case we must make sure we've initialized ourselves, this - // happens the first time egl_get_display() is called. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetProcAddress(procname); -} - -EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, EGLint* rects, - EGLint n_rects) { - ATRACE_CALL(); - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSwapBuffersWithDamageKHR(dpy, draw, rects, n_rects); -} - -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { - ATRACE_CALL(); - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSwapBuffers(dpy, surface); -} - -EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCopyBuffers(dpy, surface, target); -} - -const char* eglQueryString(EGLDisplay dpy, EGLint name) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryString(dpy, name); -} - -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryStringImplementationANDROID(dpy, name); -} - -EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSurfaceAttrib(dpy, surface, attribute, value); -} - -EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglBindTexImage(dpy, surface, buffer); -} - -EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglReleaseTexImage(dpy, surface, buffer); -} - -EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSwapInterval(dpy, interval); -} - -EGLBoolean eglWaitClient(void) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglWaitClient(); -} - -EGLBoolean eglBindAPI(EGLenum api) { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglBindAPI(api); -} - -EGLenum eglQueryAPI(void) { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryAPI(); -} - -EGLBoolean eglReleaseThread(void) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglReleaseThread(); -} - -EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, - EGLConfig config, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, - attrib_list); -} - -EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglLockSurfaceKHR(dpy, surface, attrib_list); -} - -EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglUnlockSurfaceKHR(dpy, surface); -} - -EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, - EGLClientBuffer buffer, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); -} - -EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroyImageKHR(dpy, img); -} - -EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateSyncKHR(dpy, type, attrib_list); -} - -EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroySyncKHR(dpy, sync); -} - -EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSignalSyncKHR(dpy, sync, mode); -} - -EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglClientWaitSyncKHR(dpy, sync, flags, timeout); -} - -EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetSyncAttribKHR(dpy, sync, attribute, value); -} - -EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateStreamKHR(dpy, attrib_list); -} - -EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDestroyStreamKHR(dpy, stream); -} - -EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLint value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamAttribKHR(dpy, stream, attribute, value); -} - -EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLint* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryStreamKHR(dpy, stream, attribute, value); -} - -EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLuint64KHR* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryStreamu64KHR(dpy, stream, attribute, value); -} - -EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, - EGLTimeKHR* value) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglQueryStreamTimeKHR(dpy, stream, attribute, value); -} - -EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, - const EGLint* attrib_list) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateStreamProducerSurfaceKHR(dpy, config, stream, attrib_list); -} - -EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamConsumerGLTextureExternalKHR(dpy, stream); -} - -EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamConsumerAcquireKHR(dpy, stream); -} - -EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglStreamConsumerReleaseKHR(dpy, stream); -} - -EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetStreamFileDescriptorKHR(dpy, stream); -} - -EGLStreamKHR eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, - EGLNativeFileDescriptorKHR file_descriptor) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglCreateStreamFromFileDescriptorKHR(dpy, file_descriptor); -} - -EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglWaitSyncKHR(dpy, sync, flags); -} - -EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglDupNativeFenceFDANDROID(dpy, sync); -} - -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglPresentationTimeANDROID(dpy, surface, time); -} - -EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer* buffer) { - clearError(); - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetNativeClientBufferANDROID(buffer); -} - -EGLuint64NV eglGetSystemTimeFrequencyNV() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetSystemTimeFrequencyNV(); -} - -EGLuint64NV eglGetSystemTimeNV() { - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetSystemTimeNV(); -} - -EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, EGLint* rects, - EGLint n_rects) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglSetDamageRegionKHR(dpy, surface, rects, n_rects); -} - -EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR* frameId) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetNextFrameIdANDROID(dpy, surface, frameId); -} - -EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, - const EGLint* names, EGLnsecsANDROID* values) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetCompositorTimingANDROID(dpy, surface, numTimestamps, names, values); -} - -EGLBoolean eglGetCompositorTimingSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint name) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetCompositorTimingSupportedANDROID(dpy, surface, name); -} - -EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, - EGLint numTimestamps, const EGLint* timestamps, - EGLnsecsANDROID* values) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetFrameTimestampsANDROID(dpy, surface, frameId, numTimestamps, - timestamps, values); -} - -EGLBoolean eglGetFrameTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, - EGLint timestamp) { - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - return cnx->platform.eglGetFrameTimestampSupportedANDROID(dpy, surface, timestamp); -} diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 296ee44ce5..d2dc514ff2 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -16,8 +16,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "egl_platform_entries.h" - #include #include #include @@ -270,19 +268,30 @@ extern EGLBoolean egl_init_drivers(); extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS]; extern gl_hooks_t gHooksTrace; +} // namespace android; + + // ---------------------------------------------------------------------------- +static inline void clearError() { egl_tls_t::clearError(); } static inline EGLContext getContext() { return egl_tls_t::getContext(); } // ---------------------------------------------------------------------------- -EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display) +EGLDisplay eglGetDisplay(EGLNativeDisplayType display) { + ATRACE_CALL(); + clearError(); + uintptr_t index = reinterpret_cast(display); if (index >= NUM_DISPLAYS) { return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); } + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); + } + EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); return dpy; } @@ -291,8 +300,10 @@ EGLDisplay eglGetDisplayImpl(EGLNativeDisplayType display) // Initialization // ---------------------------------------------------------------------------- -EGLBoolean eglInitializeImpl(EGLDisplay dpy, EGLint *major, EGLint *minor) +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) { + clearError(); + egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -301,12 +312,14 @@ EGLBoolean eglInitializeImpl(EGLDisplay dpy, EGLint *major, EGLint *minor) return res; } -EGLBoolean eglTerminateImpl(EGLDisplay dpy) +EGLBoolean eglTerminate(EGLDisplay dpy) { // NOTE: don't unload the drivers b/c some APIs can be called // after eglTerminate() has been called. eglTerminate() only // terminates an EGLDisplay, not a EGL itself. + clearError(); + egl_display_ptr dp = get_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -319,10 +332,12 @@ EGLBoolean eglTerminateImpl(EGLDisplay dpy) // configuration // ---------------------------------------------------------------------------- -EGLBoolean eglGetConfigsImpl(EGLDisplay dpy, - EGLConfig *configs, - EGLint config_size, EGLint *num_config) +EGLBoolean eglGetConfigs( EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, EGLint *num_config) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -342,10 +357,12 @@ EGLBoolean eglGetConfigsImpl(EGLDisplay dpy, return res; } -EGLBoolean eglChooseConfigImpl( EGLDisplay dpy, const EGLint *attrib_list, - EGLConfig *configs, EGLint config_size, - EGLint *num_config) +EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -419,9 +436,11 @@ EGLBoolean eglChooseConfigImpl( EGLDisplay dpy, const EGLint *attrib_list, return res; } -EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config, +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { + clearError(); + egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -682,11 +701,12 @@ EGLBoolean sendSurfaceMetadata(egl_surface_t* s) { return EGL_TRUE; } -EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) +EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) { const EGLint *origAttribList = attrib_list; + clearError(); egl_connection_t* cnx = nullptr; egl_display_ptr dp = validate_display_connection(dpy, cnx); @@ -771,10 +791,12 @@ EGLSurface eglCreateWindowSurfaceImpl( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePixmapSurfaceImpl( EGLDisplay dpy, EGLConfig config, - NativePixmapType pixmap, - const EGLint *attrib_list) +EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, + NativePixmapType pixmap, + const EGLint *attrib_list) { + clearError(); + egl_connection_t* cnx = nullptr; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { @@ -804,9 +826,11 @@ EGLSurface eglCreatePixmapSurfaceImpl( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list) +EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) { + clearError(); + egl_connection_t* cnx = nullptr; egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { @@ -836,8 +860,10 @@ EGLSurface eglCreatePbufferSurfaceImpl( EGLDisplay dpy, EGLConfig config, return EGL_NO_SURFACE; } -EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -853,9 +879,11 @@ EGLBoolean eglDestroySurfaceImpl(EGLDisplay dpy, EGLSurface surface) return result; } -EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint *value) +EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -874,7 +902,10 @@ EGLBoolean eglQuerySurfaceImpl( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value); } -void EGLAPI eglBeginFrameImpl(EGLDisplay dpy, EGLSurface surface) { +void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { + ATRACE_CALL(); + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return; @@ -890,9 +921,11 @@ void EGLAPI eglBeginFrameImpl(EGLDisplay dpy, EGLSurface surface) { // Contexts // ---------------------------------------------------------------------------- -EGLContext eglCreateContextImpl(EGLDisplay dpy, EGLConfig config, - EGLContext share_list, const EGLint *attrib_list) +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_list, const EGLint *attrib_list) { + clearError(); + egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (dp) { @@ -929,8 +962,10 @@ EGLContext eglCreateContextImpl(EGLDisplay dpy, EGLConfig config, return EGL_NO_CONTEXT; } -EGLBoolean eglDestroyContextImpl(EGLDisplay dpy, EGLContext ctx) +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -947,9 +982,11 @@ EGLBoolean eglDestroyContextImpl(EGLDisplay dpy, EGLContext ctx) return result; } -EGLBoolean eglMakeCurrentImpl( EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx) +EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx) { + clearError(); + egl_display_ptr dp = validate_display(dpy); if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -1039,9 +1076,12 @@ EGLBoolean eglMakeCurrentImpl( EGLDisplay dpy, EGLSurface draw, return result; } -EGLBoolean eglQueryContextImpl( EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value) + +EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1054,19 +1094,24 @@ EGLBoolean eglQueryContextImpl( EGLDisplay dpy, EGLContext ctx, } -EGLContext eglGetCurrentContextImpl(void) +EGLContext eglGetCurrentContext(void) { // could be called before eglInitialize(), but we wouldn't have a context // then, and this function would correctly return EGL_NO_CONTEXT. + + clearError(); + EGLContext ctx = getContext(); return ctx; } -EGLSurface eglGetCurrentSurfaceImpl(EGLint readdraw) +EGLSurface eglGetCurrentSurface(EGLint readdraw) { // could be called before eglInitialize(), but we wouldn't have a context // then, and this function would correctly return EGL_NO_SURFACE. + clearError(); + EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); @@ -1080,11 +1125,13 @@ EGLSurface eglGetCurrentSurfaceImpl(EGLint readdraw) return EGL_NO_SURFACE; } -EGLDisplay eglGetCurrentDisplayImpl(void) +EGLDisplay eglGetCurrentDisplay(void) { // could be called before eglInitialize(), but we wouldn't have a context // then, and this function would correctly return EGL_NO_DISPLAY. + clearError(); + EGLContext ctx = getContext(); if (ctx) { egl_context_t const * const c = get_context(ctx); @@ -1094,8 +1141,10 @@ EGLDisplay eglGetCurrentDisplayImpl(void) return EGL_NO_DISPLAY; } -EGLBoolean eglWaitGLImpl(void) +EGLBoolean eglWaitGL(void) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1103,8 +1152,10 @@ EGLBoolean eglWaitGLImpl(void) return cnx->egl.eglWaitGL(); } -EGLBoolean eglWaitNativeImpl(EGLint engine) +EGLBoolean eglWaitNative(EGLint engine) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1112,7 +1163,7 @@ EGLBoolean eglWaitNativeImpl(EGLint engine) return cnx->egl.eglWaitNative(engine); } -EGLint eglGetErrorImpl(void) +EGLint eglGetError(void) { EGLint err = EGL_SUCCESS; egl_connection_t* const cnx = &gEGLImpl; @@ -1142,8 +1193,19 @@ static __eglMustCastToProperFunctionPointerType findBuiltinWrapper( return nullptr; } -__eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procname) +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) { + // eglGetProcAddress() could be the very first function called + // in which case we must make sure we've initialized ourselves, this + // happens the first time egl_get_display() is called. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + if (FILTER_EXTENSIONS(procname)) { return nullptr; } @@ -1284,9 +1346,12 @@ private: std::mutex mMutex; }; -EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, EGLint *rects, EGLint n_rects) { + ATRACE_CALL(); + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1351,14 +1416,16 @@ EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, } } -EGLBoolean eglSwapBuffersImpl(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) { - return eglSwapBuffersWithDamageKHRImpl(dpy, surface, nullptr, 0); + return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0); } -EGLBoolean eglCopyBuffersImpl( EGLDisplay dpy, EGLSurface surface, - NativePixmapType target) +EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, + NativePixmapType target) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1370,8 +1437,10 @@ EGLBoolean eglCopyBuffersImpl( EGLDisplay dpy, EGLSurface surface, return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); } -const char* eglQueryStringImpl(EGLDisplay dpy, EGLint name) +const char* eglQueryString(EGLDisplay dpy, EGLint name) { + clearError(); + // Generate an error quietly when client extensions (as defined by // EGL_EXT_client_extensions) are queried. We do not want to rely on // validate_display to generate the error as validate_display would log @@ -1400,8 +1469,10 @@ const char* eglQueryStringImpl(EGLDisplay dpy, EGLint name) return setError(EGL_BAD_PARAMETER, (const char *)nullptr); } -EGLAPI const char* eglQueryStringImplementationANDROIDImpl(EGLDisplay dpy, EGLint name) +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return (const char *) nullptr; @@ -1424,9 +1495,11 @@ EGLAPI const char* eglQueryStringImplementationANDROIDImpl(EGLDisplay dpy, EGLin // EGL 1.1 // ---------------------------------------------------------------------------- -EGLBoolean eglSurfaceAttribImpl( +EGLBoolean eglSurfaceAttrib( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1463,9 +1536,11 @@ EGLBoolean eglSurfaceAttribImpl( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglBindTexImageImpl( +EGLBoolean eglBindTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1481,9 +1556,11 @@ EGLBoolean eglBindTexImageImpl( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglReleaseTexImageImpl( +EGLBoolean eglReleaseTexImage( EGLDisplay dpy, EGLSurface surface, EGLint buffer) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1499,8 +1576,10 @@ EGLBoolean eglReleaseTexImageImpl( return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglSwapIntervalImpl(EGLDisplay dpy, EGLint interval) +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1518,8 +1597,10 @@ EGLBoolean eglSwapIntervalImpl(EGLDisplay dpy, EGLint interval) // EGL 1.2 // ---------------------------------------------------------------------------- -EGLBoolean eglWaitClientImpl(void) +EGLBoolean eglWaitClient(void) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (!cnx->dso) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); @@ -1533,8 +1614,14 @@ EGLBoolean eglWaitClientImpl(void) return res; } -EGLBoolean eglBindAPIImpl(EGLenum api) +EGLBoolean eglBindAPI(EGLenum api) { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + // bind this API on all EGLs EGLBoolean res = EGL_TRUE; egl_connection_t* const cnx = &gEGLImpl; @@ -1544,8 +1631,14 @@ EGLBoolean eglBindAPIImpl(EGLenum api) return res; } -EGLenum eglQueryAPIImpl(void) +EGLenum eglQueryAPI(void) { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglQueryAPI) { return cnx->egl.eglQueryAPI(); @@ -1555,8 +1648,10 @@ EGLenum eglQueryAPIImpl(void) return EGL_OPENGL_ES_API; } -EGLBoolean eglReleaseThreadImpl(void) +EGLBoolean eglReleaseThread(void) { + clearError(); + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && cnx->egl.eglReleaseThread) { cnx->egl.eglReleaseThread(); @@ -1569,10 +1664,12 @@ EGLBoolean eglReleaseThreadImpl(void) return EGL_TRUE; } -EGLSurface eglCreatePbufferFromClientBufferImpl( +EGLSurface eglCreatePbufferFromClientBuffer( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) { + clearError(); + egl_connection_t* cnx = nullptr; const egl_display_ptr dp = validate_display_connection(dpy, cnx); if (!dp) return EGL_FALSE; @@ -1587,9 +1684,11 @@ EGLSurface eglCreatePbufferFromClientBufferImpl( // EGL_EGLEXT_VERSION 3 // ---------------------------------------------------------------------------- -EGLBoolean eglLockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1605,8 +1704,10 @@ EGLBoolean eglLockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLBoolean eglUnlockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface) +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1621,9 +1722,11 @@ EGLBoolean eglUnlockSurfaceKHRImpl(EGLDisplay dpy, EGLSurface surface) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); } -EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target, +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_IMAGE_KHR; @@ -1641,8 +1744,10 @@ EGLImageKHR eglCreateImageKHRImpl(EGLDisplay dpy, EGLContext ctx, EGLenum target return result; } -EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img) +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1659,8 +1764,10 @@ EGLBoolean eglDestroyImageKHRImpl(EGLDisplay dpy, EGLImageKHR img) // ---------------------------------------------------------------------------- -EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SYNC_KHR; @@ -1672,8 +1779,10 @@ EGLSyncKHR eglCreateSyncKHRImpl(EGLDisplay dpy, EGLenum type, const EGLint *attr return result; } -EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync) +EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1685,7 +1794,9 @@ EGLBoolean eglDestroySyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { +EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1698,9 +1809,11 @@ EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { return result; } -EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1713,9 +1826,11 @@ EGLint eglClientWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1728,8 +1843,10 @@ EGLBoolean eglGetSyncAttribKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, return result; } -EGLStreamKHR eglCreateStreamKHRImpl(EGLDisplay dpy, const EGLint *attrib_list) +EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; @@ -1742,8 +1859,10 @@ EGLStreamKHR eglCreateStreamKHRImpl(EGLDisplay dpy, const EGLint *attrib_list) return result; } -EGLBoolean eglDestroyStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) +EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1756,9 +1875,11 @@ EGLBoolean eglDestroyStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream) return result; } -EGLBoolean eglStreamAttribKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1771,9 +1892,11 @@ EGLBoolean eglStreamAttribKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1786,9 +1909,11 @@ EGLBoolean eglQueryStreamKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamu64KHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1801,9 +1926,11 @@ EGLBoolean eglQueryStreamu64KHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLBoolean eglQueryStreamTimeKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, +EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1816,9 +1943,11 @@ EGLBoolean eglQueryStreamTimeKHRImpl(EGLDisplay dpy, EGLStreamKHR stream, return result; } -EGLSurface eglCreateStreamProducerSurfaceKHRImpl(EGLDisplay dpy, EGLConfig config, +EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list) { + clearError(); + egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_SURFACE; @@ -1835,9 +1964,11 @@ EGLSurface eglCreateStreamProducerSurfaceKHRImpl(EGLDisplay dpy, EGLConfig confi return EGL_NO_SURFACE; } -EGLBoolean eglStreamConsumerGLTextureExternalKHRImpl(EGLDisplay dpy, +EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1850,9 +1981,11 @@ EGLBoolean eglStreamConsumerGLTextureExternalKHRImpl(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerAcquireKHRImpl(EGLDisplay dpy, +EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1865,9 +1998,11 @@ EGLBoolean eglStreamConsumerAcquireKHRImpl(EGLDisplay dpy, return result; } -EGLBoolean eglStreamConsumerReleaseKHRImpl(EGLDisplay dpy, +EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; @@ -1880,9 +2015,11 @@ EGLBoolean eglStreamConsumerReleaseKHRImpl(EGLDisplay dpy, return result; } -EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHRImpl( +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( EGLDisplay dpy, EGLStreamKHR stream) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; @@ -1895,9 +2032,11 @@ EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHRImpl( return result; } -EGLStreamKHR eglCreateStreamFromFileDescriptorKHRImpl( +EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_STREAM_KHR; @@ -1914,7 +2053,8 @@ EGLStreamKHR eglCreateStreamFromFileDescriptorKHRImpl( // EGL_EGLEXT_VERSION 15 // ---------------------------------------------------------------------------- -EGLint eglWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { +EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { + clearError(); const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_FALSE; EGLint result = EGL_FALSE; @@ -1929,8 +2069,10 @@ EGLint eglWaitSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { // ANDROID extensions // ---------------------------------------------------------------------------- -EGLint eglDupNativeFenceFDANDROIDImpl(EGLDisplay dpy, EGLSyncKHR sync) +EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; @@ -1942,9 +2084,11 @@ EGLint eglDupNativeFenceFDANDROIDImpl(EGLDisplay dpy, EGLSyncKHR sync) return result; } -EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return EGL_FALSE; @@ -1962,7 +2106,8 @@ EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLClientBuffer eglGetNativeClientBufferANDROIDImpl(const AHardwareBuffer *buffer) { +EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { + clearError(); // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus // this function cannot be implemented when this libEGL is built for // vendors. @@ -1977,8 +2122,14 @@ EGLClientBuffer eglGetNativeClientBufferANDROIDImpl(const AHardwareBuffer *buffe // ---------------------------------------------------------------------------- // NVIDIA extensions // ---------------------------------------------------------------------------- -EGLuint64NV eglGetSystemTimeFrequencyNVImpl() +EGLuint64NV eglGetSystemTimeFrequencyNV() { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; @@ -1989,8 +2140,14 @@ EGLuint64NV eglGetSystemTimeFrequencyNVImpl() return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); } -EGLuint64NV eglGetSystemTimeNVImpl() +EGLuint64NV eglGetSystemTimeNV() { + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + EGLuint64NV ret = 0; egl_connection_t* const cnx = &gEGLImpl; @@ -2004,9 +2161,11 @@ EGLuint64NV eglGetSystemTimeNVImpl() // ---------------------------------------------------------------------------- // Partial update extension // ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHRImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { setError(EGL_BAD_DISPLAY, EGL_FALSE); @@ -2028,8 +2187,10 @@ EGLBoolean eglSetDamageRegionKHRImpl(EGLDisplay dpy, EGLSurface surface, return EGL_FALSE; } -EGLBoolean eglGetNextFrameIdANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2060,9 +2221,11 @@ EGLBoolean eglGetNextFrameIdANDROIDImpl(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; } -EGLBoolean eglGetCompositorTimingANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2115,9 +2278,11 @@ EGLBoolean eglGetCompositorTimingANDROIDImpl(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetCompositorTimingSupportedANDROIDImpl( +EGLBoolean eglGetCompositorTimingSupportedANDROID( EGLDisplay dpy, EGLSurface surface, EGLint name) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2145,10 +2310,12 @@ EGLBoolean eglGetCompositorTimingSupportedANDROIDImpl( } } -EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface, +EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2231,9 +2398,11 @@ EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface, } } -EGLBoolean eglGetFrameTimestampSupportedANDROIDImpl( +EGLBoolean eglGetFrameTimestampSupportedANDROID( EGLDisplay dpy, EGLSurface surface, EGLint timestamp) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); if (!dp) { return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); @@ -2274,182 +2443,3 @@ EGLBoolean eglGetFrameTimestampSupportedANDROIDImpl( return EGL_FALSE; } } - -const GLubyte * glGetStringImpl(GLenum name) { - const GLubyte * ret = egl_get_string_for_current_context(name); - if (ret == NULL) { - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; - if(_c) ret = _c->glGetString(name); - } - return ret; -} - -const GLubyte * glGetStringiImpl(GLenum name, GLuint index) { - const GLubyte * ret = egl_get_string_for_current_context(name, index); - if (ret == NULL) { - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; - if(_c) ret = _c->glGetStringi(name, index); - } - return ret; -} - -void glGetBooleanvImpl(GLenum pname, GLboolean * data) { - if (pname == GL_NUM_EXTENSIONS) { - int num_exts = egl_get_num_extensions_for_current_context(); - if (num_exts >= 0) { - *data = num_exts > 0 ? GL_TRUE : GL_FALSE; - return; - } - } - - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; - if (_c) _c->glGetBooleanv(pname, data); -} - -void glGetFloatvImpl(GLenum pname, GLfloat * data) { - if (pname == GL_NUM_EXTENSIONS) { - int num_exts = egl_get_num_extensions_for_current_context(); - if (num_exts >= 0) { - *data = (GLfloat)num_exts; - return; - } - } - - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; - if (_c) _c->glGetFloatv(pname, data); -} - -void glGetIntegervImpl(GLenum pname, GLint * data) { - if (pname == GL_NUM_EXTENSIONS) { - int num_exts = egl_get_num_extensions_for_current_context(); - if (num_exts >= 0) { - *data = (GLint)num_exts; - return; - } - } - - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; - if (_c) _c->glGetIntegerv(pname, data); -} - -void glGetInteger64vImpl(GLenum pname, GLint64 * data) { - if (pname == GL_NUM_EXTENSIONS) { - int num_exts = egl_get_num_extensions_for_current_context(); - if (num_exts >= 0) { - *data = (GLint64)num_exts; - return; - } - } - - gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; - if (_c) _c->glGetInteger64v(pname, data); -} - -struct implementation_map_t { - const char* name; - EGLFuncPointer address; -}; - -static const implementation_map_t sPlatformImplMap[] = { - { "eglGetDisplay", (EGLFuncPointer)&eglGetDisplayImpl }, - { "eglInitialize", (EGLFuncPointer)&eglInitializeImpl }, - { "eglTerminate", (EGLFuncPointer)&eglTerminateImpl }, - { "eglGetConfigs", (EGLFuncPointer)&eglGetConfigsImpl }, - { "eglChooseConfig", (EGLFuncPointer)&eglChooseConfigImpl }, - { "eglGetConfigAttrib", (EGLFuncPointer)&eglGetConfigAttribImpl }, - { "eglCreateWindowSurface", (EGLFuncPointer)&eglCreateWindowSurfaceImpl }, - { "eglCreatePixmapSurface", (EGLFuncPointer)&eglCreatePixmapSurfaceImpl }, - { "eglCreatePbufferSurface", (EGLFuncPointer)&eglCreatePbufferSurfaceImpl }, - { "eglDestroySurface", (EGLFuncPointer)&eglDestroySurfaceImpl }, - { "eglQuerySurface", (EGLFuncPointer)&eglQuerySurfaceImpl }, - { "eglBeginFrame", (EGLFuncPointer)&eglBeginFrameImpl }, - { "eglCreateContext", (EGLFuncPointer)&eglCreateContextImpl }, - { "eglDestroyContext", (EGLFuncPointer)&eglDestroyContextImpl }, - { "eglMakeCurrent", (EGLFuncPointer)&eglMakeCurrentImpl }, - { "eglQueryContext", (EGLFuncPointer)&eglQueryContextImpl }, - { "eglGetCurrentContext", (EGLFuncPointer)&eglGetCurrentContextImpl }, - { "eglGetCurrentSurface", (EGLFuncPointer)&eglGetCurrentSurfaceImpl }, - { "eglGetCurrentDisplay", (EGLFuncPointer)&eglGetCurrentDisplayImpl }, - { "eglWaitGL", (EGLFuncPointer)&eglWaitGLImpl }, - { "eglWaitNative", (EGLFuncPointer)&eglWaitNativeImpl }, - { "eglGetError", (EGLFuncPointer)&eglGetErrorImpl }, - { "eglSwapBuffersWithDamageKHR", (EGLFuncPointer)&eglSwapBuffersWithDamageKHRImpl }, - { "eglGetProcAddress", (EGLFuncPointer)&eglGetProcAddressImpl }, - { "eglSwapBuffers", (EGLFuncPointer)&eglSwapBuffersImpl }, - { "eglCopyBuffers", (EGLFuncPointer)&eglCopyBuffersImpl }, - { "eglQueryString", (EGLFuncPointer)&eglQueryStringImpl }, - { "eglQueryStringImplementationANDROID", (EGLFuncPointer)&eglQueryStringImplementationANDROIDImpl }, - { "eglSurfaceAttrib", (EGLFuncPointer)&eglSurfaceAttribImpl }, - { "eglBindTexImage", (EGLFuncPointer)&eglBindTexImageImpl }, - { "eglReleaseTexImage", (EGLFuncPointer)&eglReleaseTexImageImpl }, - { "eglSwapInterval", (EGLFuncPointer)&eglSwapIntervalImpl }, - { "eglWaitClient", (EGLFuncPointer)&eglWaitClientImpl }, - { "eglBindAPI", (EGLFuncPointer)&eglBindAPIImpl }, - { "eglQueryAPI", (EGLFuncPointer)&eglQueryAPIImpl }, - { "eglReleaseThread", (EGLFuncPointer)&eglReleaseThreadImpl }, - { "eglCreatePbufferFromClientBuffer", (EGLFuncPointer)&eglCreatePbufferFromClientBufferImpl }, - { "eglLockSurfaceKHR", (EGLFuncPointer)&eglLockSurfaceKHRImpl }, - { "eglUnlockSurfaceKHR", (EGLFuncPointer)&eglUnlockSurfaceKHRImpl }, - { "eglCreateImageKHR", (EGLFuncPointer)&eglCreateImageKHRImpl }, - { "eglDestroyImageKHR", (EGLFuncPointer)&eglDestroyImageKHRImpl }, - { "eglCreateSyncKHR", (EGLFuncPointer)&eglCreateSyncKHRImpl }, - { "eglDestroySyncKHR", (EGLFuncPointer)&eglDestroySyncKHRImpl }, - { "eglSignalSyncKHR", (EGLFuncPointer)&eglSignalSyncKHRImpl }, - { "eglClientWaitSyncKHR", (EGLFuncPointer)&eglClientWaitSyncKHRImpl }, - { "eglGetSyncAttribKHR", (EGLFuncPointer)&eglGetSyncAttribKHRImpl }, - { "eglCreateStreamKHR", (EGLFuncPointer)&eglCreateStreamKHRImpl }, - { "eglDestroyStreamKHR", (EGLFuncPointer)&eglDestroyStreamKHRImpl }, - { "eglStreamAttribKHR", (EGLFuncPointer)&eglStreamAttribKHRImpl }, - { "eglQueryStreamKHR", (EGLFuncPointer)&eglQueryStreamKHRImpl }, - { "eglQueryStreamu64KHR", (EGLFuncPointer)&eglQueryStreamu64KHRImpl }, - { "eglQueryStreamTimeKHR", (EGLFuncPointer)&eglQueryStreamTimeKHRImpl }, - { "eglCreateStreamProducerSurfaceKHR", (EGLFuncPointer)&eglCreateStreamProducerSurfaceKHRImpl }, - { "eglStreamConsumerGLTextureExternalKHR", (EGLFuncPointer)&eglStreamConsumerGLTextureExternalKHRImpl }, - { "eglStreamConsumerAcquireKHR", (EGLFuncPointer)&eglStreamConsumerAcquireKHRImpl }, - { "eglStreamConsumerReleaseKHR", (EGLFuncPointer)&eglStreamConsumerReleaseKHRImpl }, - { "eglGetStreamFileDescriptorKHR", (EGLFuncPointer)&eglGetStreamFileDescriptorKHRImpl }, - { "eglCreateStreamFromFileDescriptorKHR", (EGLFuncPointer)&eglCreateStreamFromFileDescriptorKHRImpl }, - { "eglWaitSyncKHR", (EGLFuncPointer)&eglWaitSyncKHRImpl }, - { "eglDupNativeFenceFDANDROID", (EGLFuncPointer)&eglDupNativeFenceFDANDROIDImpl }, - { "eglPresentationTimeANDROID", (EGLFuncPointer)&eglPresentationTimeANDROIDImpl }, - { "eglGetNativeClientBufferANDROID", (EGLFuncPointer)&eglGetNativeClientBufferANDROIDImpl }, - { "eglGetSystemTimeFrequencyNV", (EGLFuncPointer)&eglGetSystemTimeFrequencyNVImpl }, - { "eglGetSystemTimeNV", (EGLFuncPointer)&eglGetSystemTimeNVImpl }, - { "eglSetDamageRegionKHR", (EGLFuncPointer)&eglSetDamageRegionKHRImpl }, - { "eglGetNextFrameIdANDROID", (EGLFuncPointer)&eglGetNextFrameIdANDROIDImpl }, - { "eglGetCompositorTimingANDROID", (EGLFuncPointer)&eglGetCompositorTimingANDROIDImpl }, - { "eglGetCompositorTimingSupportedANDROID", (EGLFuncPointer)&eglGetCompositorTimingSupportedANDROIDImpl }, - { "eglGetFrameTimestampsANDROID", (EGLFuncPointer)&eglGetFrameTimestampsANDROIDImpl }, - { "eglGetFrameTimestampSupportedANDROID", (EGLFuncPointer)&eglGetFrameTimestampSupportedANDROIDImpl }, - { "glGetString", (EGLFuncPointer)&glGetStringImpl }, - { "glGetStringi", (EGLFuncPointer)&glGetStringiImpl }, - { "glGetBooleanv", (EGLFuncPointer)&glGetBooleanvImpl }, - { "glGetFloatv", (EGLFuncPointer)&glGetFloatvImpl }, - { "glGetIntegerv", (EGLFuncPointer)&glGetIntegervImpl }, - { "glGetInteger64v", (EGLFuncPointer)&glGetInteger64vImpl }, -}; - -EGLFuncPointer FindPlatformImplAddr(const char* name) -{ - static const bool DEBUG = false; - - if (name == nullptr) { - ALOGV("FindPlatformImplAddr called with null name"); - return nullptr; - } - - for (int i = 0; i < NELEM(sPlatformImplMap); i++) { - if (sPlatformImplMap[i].name == nullptr) { - ALOGV("FindPlatformImplAddr found nullptr for sPlatformImplMap[%i].name (%s)", i, name); - return nullptr; - } - if (!strcmp(name, sPlatformImplMap[i].name)) { - ALOGV("FindPlatformImplAddr found %llu for sPlatformImplMap[%i].address (%s)", (unsigned long long)sPlatformImplMap[i].address, i, name); - return sPlatformImplMap[i].address; - } - } - - ALOGV("FindPlatformImplAddr did not find an entry for %s", name); - return nullptr; -} -} // namespace android diff --git a/opengl/libs/EGL/egl_platform_entries.h b/opengl/libs/EGL/egl_platform_entries.h deleted file mode 100644 index 7cd80d6dc2..0000000000 --- a/opengl/libs/EGL/egl_platform_entries.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -#ifndef ANDROID_EGLAPI_H -#define ANDROID_EGLAPI_H - -#include - -typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer; - -namespace android { - -EGLFuncPointer FindPlatformImplAddr(const char* name); - -}; // namespace android - -#endif // ANDROID_EGLAPI_H - diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h index 1a88678964..4990af6edd 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -38,16 +38,12 @@ struct egl_connection_t { }; inline egl_connection_t() : dso(nullptr) { } - void * dso; gl_hooks_t * hooks[2]; EGLint major; EGLint minor; egl_t egl; - // Functions implemented or redirected by platform libraries - platform_impl_t platform; - void* libEgl; void* libGles1; void* libGles2; @@ -67,7 +63,6 @@ extern "C" void gl_noop(); extern char const * const gl_names[]; extern char const * const egl_names[]; -extern char const * const platform_names[]; extern egl_connection_t gEGLImpl; diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index 65f50f54fb..f7fde9625f 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -301,31 +301,71 @@ extern "C" { } const GLubyte * glGetString(GLenum name) { - egl_connection_t* const cnx = egl_get_connection(); - return cnx->platform.glGetString(name); + const GLubyte * ret = egl_get_string_for_current_context(name); + if (ret == NULL) { + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if(_c) ret = _c->glGetString(name); + } + return ret; } const GLubyte * glGetStringi(GLenum name, GLuint index) { - egl_connection_t* const cnx = egl_get_connection(); - return cnx->platform.glGetStringi(name, index); + const GLubyte * ret = egl_get_string_for_current_context(name, index); + if (ret == NULL) { + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if(_c) ret = _c->glGetStringi(name, index); + } + return ret; } void glGetBooleanv(GLenum pname, GLboolean * data) { - egl_connection_t* const cnx = egl_get_connection(); - return cnx->platform.glGetBooleanv(pname, data); + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = num_exts > 0 ? GL_TRUE : GL_FALSE; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetBooleanv(pname, data); } void glGetFloatv(GLenum pname, GLfloat * data) { - egl_connection_t* const cnx = egl_get_connection(); - return cnx->platform.glGetFloatv(pname, data); + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = (GLfloat)num_exts; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetFloatv(pname, data); } void glGetIntegerv(GLenum pname, GLint * data) { - egl_connection_t* const cnx = egl_get_connection(); - return cnx->platform.glGetIntegerv(pname, data); + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = (GLint)num_exts; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetIntegerv(pname, data); } void glGetInteger64v(GLenum pname, GLint64 * data) { - egl_connection_t* const cnx = egl_get_connection(); - return cnx->platform.glGetInteger64v(pname, data); + if (pname == GL_NUM_EXTENSIONS) { + int num_exts = egl_get_num_extensions_for_current_context(); + if (num_exts >= 0) { + *data = (GLint64)num_exts; + return; + } + } + + gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; + if (_c) _c->glGetInteger64v(pname, data); } diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index 0af050175b..a8855efa57 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -21,18 +21,15 @@ #include #include -#include "EGL/egldefs.h" #include "hooks.h" // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- - EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name); EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index); EGLAPI GLint egl_get_num_extensions_for_current_context(); -EGLAPI egl_connection_t* egl_get_connection(); // ---------------------------------------------------------------------------- }; // namespace android diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h index 63a0e140cc..81dbe0e34b 100644 --- a/opengl/libs/hooks.h +++ b/opengl/libs/hooks.h @@ -59,10 +59,6 @@ namespace android { #define GL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__); #define EGL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__); -struct platform_impl_t { - #include "platform_entries.in" -}; - struct egl_t { #include "EGL/egl_entries.in" }; diff --git a/opengl/libs/platform_entries.in b/opengl/libs/platform_entries.in deleted file mode 100644 index b28f6ccac8..0000000000 --- a/opengl/libs/platform_entries.in +++ /dev/null @@ -1,76 +0,0 @@ -EGL_ENTRY(EGLDisplay, eglGetDisplay, EGLNativeDisplayType) -EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*) -EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay) -EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*) -EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*) -EGL_ENTRY(EGLBoolean, eglGetConfigAttrib, EGLDisplay, EGLConfig, EGLint, EGLint*) -EGL_ENTRY(EGLSurface, eglCreateWindowSurface, EGLDisplay, EGLConfig, NativeWindowType, const EGLint*) -EGL_ENTRY(EGLSurface, eglCreatePixmapSurface, EGLDisplay, EGLConfig, NativePixmapType, const EGLint*) -EGL_ENTRY(EGLSurface, eglCreatePbufferSurface, EGLDisplay, EGLConfig, const EGLint*) -EGL_ENTRY(EGLBoolean, eglDestroySurface, EGLDisplay, EGLSurface) -EGL_ENTRY(EGLBoolean, eglQuerySurface, EGLDisplay, EGLSurface, EGLint, EGLint*) -EGL_ENTRY(void, eglBeginFrame, EGLDisplay, EGLSurface) -EGL_ENTRY(EGLContext, eglCreateContext, EGLDisplay, EGLConfig, EGLContext, const EGLint*) -EGL_ENTRY(EGLBoolean, eglDestroyContext, EGLDisplay, EGLContext) -EGL_ENTRY(EGLBoolean, eglMakeCurrent, EGLDisplay, EGLSurface, EGLSurface, EGLContext) -EGL_ENTRY(EGLBoolean, eglQueryContext, EGLDisplay, EGLContext, EGLint, EGLint*) -EGL_ENTRY(EGLContext, eglGetCurrentContext, void) -EGL_ENTRY(EGLSurface, eglGetCurrentSurface, EGLint) -EGL_ENTRY(EGLDisplay, eglGetCurrentDisplay, void) -EGL_ENTRY(EGLBoolean, eglWaitGL, void) -EGL_ENTRY(EGLBoolean, eglWaitNative, EGLint) -EGL_ENTRY(EGLint, eglGetError, void) -EGL_ENTRY(__eglMustCastToProperFunctionPointerType, eglGetProcAddress, const char*) -EGL_ENTRY(EGLBoolean, eglSwapBuffersWithDamageKHR, EGLDisplay, EGLSurface, EGLint*, EGLint) -EGL_ENTRY(EGLBoolean, eglSwapBuffers, EGLDisplay, EGLSurface) -EGL_ENTRY(EGLBoolean, eglCopyBuffers, EGLDisplay, EGLSurface, NativePixmapType) -EGL_ENTRY(const char*, eglQueryString, EGLDisplay, EGLint) -EGL_ENTRY(const char*, eglQueryStringImplementationANDROID, EGLDisplay, EGLint) -EGL_ENTRY(EGLBoolean, eglSurfaceAttrib, EGLDisplay, EGLSurface, EGLint, EGLint) -EGL_ENTRY(EGLBoolean, eglBindTexImage, EGLDisplay, EGLSurface, EGLint) -EGL_ENTRY(EGLBoolean, eglReleaseTexImage, EGLDisplay, EGLSurface, EGLint) -EGL_ENTRY(EGLBoolean, eglSwapInterval, EGLDisplay, EGLint) -EGL_ENTRY(EGLBoolean, eglWaitClient, void) -EGL_ENTRY(EGLBoolean, eglBindAPI, EGLenum) -EGL_ENTRY(EGLenum, eglQueryAPI, void) -EGL_ENTRY(EGLBoolean, eglReleaseThread, void) -EGL_ENTRY(EGLSurface, eglCreatePbufferFromClientBuffer, EGLDisplay, EGLenum, EGLClientBuffer, EGLConfig, const EGLint*) -EGL_ENTRY(EGLBoolean, eglLockSurfaceKHR, EGLDisplay, EGLSurface, const EGLint*) -EGL_ENTRY(EGLBoolean, eglUnlockSurfaceKHR, EGLDisplay, EGLSurface) -EGL_ENTRY(EGLImageKHR, eglCreateImageKHR, EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint*) -EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR) -EGL_ENTRY(EGLSyncKHR, eglCreateSyncKHR, EGLDisplay, EGLenum, const EGLint*) -EGL_ENTRY(EGLBoolean, eglDestroySyncKHR, EGLDisplay, EGLSyncKHR) -EGL_ENTRY(EGLBoolean, eglSignalSyncKHR, EGLDisplay, EGLSyncKHR, EGLenum) -EGL_ENTRY(EGLint, eglClientWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR) -EGL_ENTRY(EGLBoolean, eglGetSyncAttribKHR, EGLDisplay, EGLSyncKHR, EGLint, EGLint*) -EGL_ENTRY(EGLStreamKHR, eglCreateStreamKHR, EGLDisplay, const EGLint*) -EGL_ENTRY(EGLBoolean, eglDestroyStreamKHR, EGLDisplay, EGLStreamKHR) -EGL_ENTRY(EGLBoolean, eglStreamAttribKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint) -EGL_ENTRY(EGLBoolean, eglQueryStreamKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLint*) -EGL_ENTRY(EGLBoolean, eglQueryStreamu64KHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLuint64KHR*) -EGL_ENTRY(EGLBoolean, eglQueryStreamTimeKHR, EGLDisplay, EGLStreamKHR, EGLenum, EGLTimeKHR*) -EGL_ENTRY(EGLSurface, eglCreateStreamProducerSurfaceKHR, EGLDisplay, EGLConfig, EGLStreamKHR, const EGLint*) -EGL_ENTRY(EGLBoolean, eglStreamConsumerGLTextureExternalKHR, EGLDisplay, EGLStreamKHR) -EGL_ENTRY(EGLBoolean, eglStreamConsumerAcquireKHR, EGLDisplay, EGLStreamKHR) -EGL_ENTRY(EGLBoolean, eglStreamConsumerReleaseKHR, EGLDisplay, EGLStreamKHR) -EGL_ENTRY(EGLNativeFileDescriptorKHR, eglGetStreamFileDescriptorKHR, EGLDisplay, EGLStreamKHR) -EGL_ENTRY(EGLStreamKHR, eglCreateStreamFromFileDescriptorKHR, EGLDisplay, EGLNativeFileDescriptorKHR) -EGL_ENTRY(EGLint, eglWaitSyncKHR, EGLDisplay, EGLSyncKHR, EGLint) -EGL_ENTRY(EGLint, eglDupNativeFenceFDANDROID, EGLDisplay, EGLSyncKHR) -EGL_ENTRY(EGLBoolean, eglPresentationTimeANDROID, EGLDisplay, EGLSurface, EGLnsecsANDROID) -EGL_ENTRY(EGLClientBuffer, eglGetNativeClientBufferANDROID, const AHardwareBuffer*) -EGL_ENTRY(EGLuint64NV, eglGetSystemTimeFrequencyNV, void) -EGL_ENTRY(EGLuint64NV, eglGetSystemTimeNV, void) -EGL_ENTRY(EGLBoolean, eglSetDamageRegionKHR, EGLDisplay, EGLSurface, EGLint*, EGLint) -EGL_ENTRY(EGLBoolean, eglGetNextFrameIdANDROID, EGLDisplay, EGLSurface, EGLuint64KHR*) -EGL_ENTRY(EGLBoolean, eglGetCompositorTimingANDROID, EGLDisplay, EGLSurface, EGLint, const EGLint*, EGLnsecsANDROID*) -EGL_ENTRY(EGLBoolean, eglGetCompositorTimingSupportedANDROID, EGLDisplay, EGLSurface, EGLint) -EGL_ENTRY(EGLBoolean, eglGetFrameTimestampsANDROID, EGLDisplay, EGLSurface, EGLuint64KHR, EGLint, const EGLint*, EGLnsecsANDROID*) -EGL_ENTRY(EGLBoolean, eglGetFrameTimestampSupportedANDROID, EGLDisplay, EGLSurface, EGLint) -GL_ENTRY(const GLubyte*, glGetString, GLenum) -GL_ENTRY(const GLubyte*, glGetStringi, GLenum, GLuint) -GL_ENTRY(void, glGetBooleanv, GLenum, GLboolean*) -GL_ENTRY(void, glGetFloatv, GLenum, GLfloat*) -GL_ENTRY(void, glGetIntegerv, GLenum, GLint*) -GL_ENTRY(void, glGetInteger64v, GLenum, GLint64*) -- cgit v1.2.3-59-g8ed1b From d38a0e32877059c93bb2485e0918f8d704b259fd Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Fri, 12 Oct 2018 14:34:50 -0600 Subject: Revert "Rename eglApi.cpp to egl_platform_entries.cpp" This reverts commit 489e5df936aed8bc96ea33bbf2fb668d129eb702. Bug: 110883880 Test: Chrome no longer crashes Change-Id: I1022ad2ccc647f35fc074422c538e39613be43c2 (cherry picked from commit 8dec3913042c8f199c79168980da8bfc78da97a1) --- opengl/libs/Android.bp | 2 +- opengl/libs/EGL/eglApi.cpp | 2445 ++++++++++++++++++++++++++++++ opengl/libs/EGL/egl_platform_entries.cpp | 2445 ------------------------------ 3 files changed, 2446 insertions(+), 2446 deletions(-) create mode 100644 opengl/libs/EGL/eglApi.cpp delete mode 100644 opengl/libs/EGL/egl_platform_entries.cpp diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index 78309d419f..2a6dee4f4f 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -141,7 +141,7 @@ cc_library_shared { "EGL/egl_display.cpp", "EGL/egl_object.cpp", "EGL/egl.cpp", - "EGL/egl_platform_entries.cpp", + "EGL/eglApi.cpp", "EGL/Loader.cpp", "EGL/egl_angle_platform.cpp", ], diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp new file mode 100644 index 0000000000..d2dc514ff2 --- /dev/null +++ b/opengl/libs/EGL/eglApi.cpp @@ -0,0 +1,2445 @@ +/* + ** Copyright 2007, 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. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../egl_impl.h" + +#include "egl_display.h" +#include "egl_object.h" +#include "egl_tls.h" +#include "egl_trace.h" + +using namespace android; + +// ---------------------------------------------------------------------------- + +namespace android { + +using nsecs_t = int64_t; + +struct extention_map_t { + const char* name; + __eglMustCastToProperFunctionPointerType address; +}; + +/* + * This is the list of EGL extensions exposed to applications. + * + * Some of them (gBuiltinExtensionString) are implemented entirely in this EGL + * wrapper and are always available. + * + * The rest (gExtensionString) depend on support in the EGL driver, and are + * only available if the driver supports them. However, some of these must be + * supported because they are used by the Android system itself; these are + * listed as mandatory below and are required by the CDD. The system *assumes* + * the mandatory extensions are present and may not function properly if some + * are missing. + * + * NOTE: Both strings MUST have a single space as the last character. + */ + +extern char const * const gBuiltinExtensionString; +extern char const * const gExtensionString; + +// clang-format off +// Extensions implemented by the EGL wrapper. +char const * const gBuiltinExtensionString = + "EGL_KHR_get_all_proc_addresses " + "EGL_ANDROID_presentation_time " + "EGL_KHR_swap_buffers_with_damage " + "EGL_ANDROID_get_native_client_buffer " + "EGL_ANDROID_front_buffer_auto_refresh " + "EGL_ANDROID_get_frame_timestamps " + "EGL_EXT_surface_SMPTE2086_metadata " + "EGL_EXT_surface_CTA861_3_metadata " + ; + +// Whitelist of extensions exposed to applications if implemented in the vendor driver. +char const * const gExtensionString = + "EGL_KHR_image " // mandatory + "EGL_KHR_image_base " // mandatory + "EGL_EXT_image_gl_colorspace " + "EGL_KHR_image_pixmap " + "EGL_KHR_lock_surface " + "EGL_KHR_gl_colorspace " + "EGL_KHR_gl_texture_2D_image " + "EGL_KHR_gl_texture_3D_image " + "EGL_KHR_gl_texture_cubemap_image " + "EGL_KHR_gl_renderbuffer_image " + "EGL_KHR_reusable_sync " + "EGL_KHR_fence_sync " + "EGL_KHR_create_context " + "EGL_KHR_config_attribs " + "EGL_KHR_surfaceless_context " + "EGL_KHR_stream " + "EGL_KHR_stream_fifo " + "EGL_KHR_stream_producer_eglsurface " + "EGL_KHR_stream_consumer_gltexture " + "EGL_KHR_stream_cross_process_fd " + "EGL_EXT_create_context_robustness " + "EGL_NV_system_time " + "EGL_ANDROID_image_native_buffer " // mandatory + "EGL_KHR_wait_sync " // strongly recommended + "EGL_ANDROID_recordable " // mandatory + "EGL_KHR_partial_update " // strongly recommended + "EGL_EXT_pixel_format_float " + "EGL_EXT_buffer_age " // strongly recommended with partial_update + "EGL_KHR_create_context_no_error " + "EGL_KHR_mutable_render_buffer " + "EGL_EXT_yuv_surface " + "EGL_EXT_protected_content " + "EGL_IMG_context_priority " + "EGL_KHR_no_config_context " + ; +// clang-format on + +// extensions not exposed to applications but used by the ANDROID system +// "EGL_ANDROID_blob_cache " // strongly recommended +// "EGL_IMG_hibernate_process " // optional +// "EGL_ANDROID_native_fence_sync " // strongly recommended +// "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1 + +/* + * EGL Extensions entry-points exposed to 3rd party applications + * (keep in sync with gExtensionString above) + * + */ +static const extention_map_t sExtensionMap[] = { + // EGL_KHR_lock_surface + { "eglLockSurfaceKHR", + (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR }, + { "eglUnlockSurfaceKHR", + (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR }, + + // EGL_KHR_image, EGL_KHR_image_base + { "eglCreateImageKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, + { "eglDestroyImageKHR", + (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, + + // EGL_KHR_reusable_sync, EGL_KHR_fence_sync + { "eglCreateSyncKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR }, + { "eglDestroySyncKHR", + (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR }, + { "eglClientWaitSyncKHR", + (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR }, + { "eglSignalSyncKHR", + (__eglMustCastToProperFunctionPointerType)&eglSignalSyncKHR }, + { "eglGetSyncAttribKHR", + (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR }, + + // EGL_NV_system_time + { "eglGetSystemTimeFrequencyNV", + (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV }, + { "eglGetSystemTimeNV", + (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV }, + + // EGL_KHR_wait_sync + { "eglWaitSyncKHR", + (__eglMustCastToProperFunctionPointerType)&eglWaitSyncKHR }, + + // EGL_ANDROID_presentation_time + { "eglPresentationTimeANDROID", + (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID }, + + // EGL_KHR_swap_buffers_with_damage + { "eglSwapBuffersWithDamageKHR", + (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR }, + + // EGL_ANDROID_get_native_client_buffer + { "eglGetNativeClientBufferANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetNativeClientBufferANDROID }, + + // EGL_KHR_partial_update + { "eglSetDamageRegionKHR", + (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR }, + + { "eglCreateStreamKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR }, + { "eglDestroyStreamKHR", + (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR }, + { "eglStreamAttribKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR }, + { "eglQueryStreamKHR", + (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR }, + { "eglQueryStreamu64KHR", + (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR }, + { "eglQueryStreamTimeKHR", + (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR }, + { "eglCreateStreamProducerSurfaceKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR }, + { "eglStreamConsumerGLTextureExternalKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR }, + { "eglStreamConsumerAcquireKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR }, + { "eglStreamConsumerReleaseKHR", + (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR }, + { "eglGetStreamFileDescriptorKHR", + (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR }, + { "eglCreateStreamFromFileDescriptorKHR", + (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR }, + + // EGL_ANDROID_get_frame_timestamps + { "eglGetNextFrameIdANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID }, + { "eglGetCompositorTimingANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingANDROID }, + { "eglGetCompositorTimingSupportedANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingSupportedANDROID }, + { "eglGetFrameTimestampsANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID }, + { "eglGetFrameTimestampSupportedANDROID", + (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID }, + + // EGL_ANDROID_native_fence_sync + { "eglDupNativeFenceFDANDROID", + (__eglMustCastToProperFunctionPointerType)&eglDupNativeFenceFDANDROID }, +}; + +/* + * These extensions entry-points should not be exposed to applications. + * They're used internally by the Android EGL layer. + */ +#define FILTER_EXTENSIONS(procname) \ + (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") || \ + !strcmp((procname), "eglHibernateProcessIMG") || \ + !strcmp((procname), "eglAwakenProcessIMG")) + +// accesses protected by sExtensionMapMutex +static std::unordered_map sGLExtentionMap; + +static int sGLExtentionSlot = 0; +static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; + +static void(*findProcAddress(const char* name, + const extention_map_t* map, size_t n))() { + for (uint32_t i=0 ; i(display); + if (index >= NUM_DISPLAYS) { + return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); + } + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); + } + + EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); + return dpy; +} + +// ---------------------------------------------------------------------------- +// Initialization +// ---------------------------------------------------------------------------- + +EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + clearError(); + + egl_display_ptr dp = get_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + + EGLBoolean res = dp->initialize(major, minor); + + return res; +} + +EGLBoolean eglTerminate(EGLDisplay dpy) +{ + // NOTE: don't unload the drivers b/c some APIs can be called + // after eglTerminate() has been called. eglTerminate() only + // terminates an EGLDisplay, not a EGL itself. + + clearError(); + + egl_display_ptr dp = get_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + + EGLBoolean res = dp->terminate(); + + return res; +} + +// ---------------------------------------------------------------------------- +// configuration +// ---------------------------------------------------------------------------- + +EGLBoolean eglGetConfigs( EGLDisplay dpy, + EGLConfig *configs, + EGLint config_size, EGLint *num_config) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + if (num_config==nullptr) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + EGLBoolean res = EGL_FALSE; + *num_config = 0; + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + res = cnx->egl.eglGetConfigs( + dp->disp.dpy, configs, config_size, num_config); + } + + return res; +} + +EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + if (num_config==nullptr) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + EGLBoolean res = EGL_FALSE; + *num_config = 0; + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + if (attrib_list) { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.egl.force_msaa", value, "false"); + + if (!strcmp(value, "true")) { + size_t attribCount = 0; + EGLint attrib = attrib_list[0]; + + // Only enable MSAA if the context is OpenGL ES 2.0 and + // if no caveat is requested + const EGLint *attribRendererable = nullptr; + const EGLint *attribCaveat = nullptr; + + // Count the number of attributes and look for + // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT + while (attrib != EGL_NONE) { + attrib = attrib_list[attribCount]; + switch (attrib) { + case EGL_RENDERABLE_TYPE: + attribRendererable = &attrib_list[attribCount]; + break; + case EGL_CONFIG_CAVEAT: + attribCaveat = &attrib_list[attribCount]; + break; + default: + break; + } + attribCount++; + } + + if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT && + (!attribCaveat || attribCaveat[1] != EGL_NONE)) { + + // Insert 2 extra attributes to force-enable MSAA 4x + EGLint aaAttribs[attribCount + 4]; + aaAttribs[0] = EGL_SAMPLE_BUFFERS; + aaAttribs[1] = 1; + aaAttribs[2] = EGL_SAMPLES; + aaAttribs[3] = 4; + + memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint)); + + EGLint numConfigAA; + EGLBoolean resAA = cnx->egl.eglChooseConfig( + dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA); + + if (resAA == EGL_TRUE && numConfigAA > 0) { + ALOGD("Enabling MSAA 4x"); + *num_config = numConfigAA; + return resAA; + } + } + } + } + + res = cnx->egl.eglChooseConfig( + dp->disp.dpy, attrib_list, configs, config_size, num_config); + } + return res; +} + +EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value) +{ + clearError(); + + egl_connection_t* cnx = nullptr; + const egl_display_ptr dp = validate_display_connection(dpy, cnx); + if (!dp) return EGL_FALSE; + + return cnx->egl.eglGetConfigAttrib( + dp->disp.dpy, config, attribute, value); +} + +// ---------------------------------------------------------------------------- +// surfaces +// ---------------------------------------------------------------------------- + +// Translates EGL color spaces to Android data spaces. +static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { + if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { + return HAL_DATASPACE_UNKNOWN; + } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { + return HAL_DATASPACE_SRGB; + } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) { + return HAL_DATASPACE_DISPLAY_P3; + } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) { + return HAL_DATASPACE_DISPLAY_P3_LINEAR; + } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) { + return HAL_DATASPACE_V0_SCRGB; + } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) { + return HAL_DATASPACE_V0_SCRGB_LINEAR; + } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) { + return HAL_DATASPACE_BT2020_LINEAR; + } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) { + return HAL_DATASPACE_BT2020_PQ; + } + return HAL_DATASPACE_UNKNOWN; +} + +// Get the colorspace value that should be reported from queries. When the colorspace +// is unknown (no attribute passed), default to reporting LINEAR. +static EGLint getReportedColorSpace(EGLint colorspace) { + return colorspace == EGL_UNKNOWN ? EGL_GL_COLORSPACE_LINEAR_KHR : colorspace; +} + +// Returns a list of color spaces understood by the vendor EGL driver. +static std::vector getDriverColorSpaces(egl_display_ptr dp, + android_pixel_format format) { + std::vector colorSpaces; + if (!dp->hasColorSpaceSupport) return colorSpaces; + + // OpenGL drivers only support sRGB encoding with 8-bit formats. + // RGB_888 is never returned by getNativePixelFormat, but is included for completeness. + const bool formatSupportsSRGBEncoding = + format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 || + format == HAL_PIXEL_FORMAT_RGB_888; + const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16; + + if (formatSupportsSRGBEncoding) { + // sRGB and linear are always supported when color space support is present. + colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); + colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); + // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats. + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_display_p3")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); + } + } + + // According to the spec, scRGB is only supported for floating point formats. + // For non-linear scRGB, the application is responsible for applying the + // transfer function. + if (formatIsFloatingPoint) { + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_scrgb")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_scrgb_linear")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); + } + } + + // BT2020 can be used with any pixel format. PQ encoding must be applied by the + // application and does not affect the behavior of OpenGL. + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_bt2020_linear")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_bt2020_pq")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); + } + + // Linear DCI-P3 simply uses different primaries than standard RGB and thus + // can be used with any pixel format. + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_display_p3_linear")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); + } + return colorSpaces; +} + +// Cleans up color space related parameters that the driver does not understand. +// If there is no color space attribute in attrib_list, colorSpace is left +// unmodified. +static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, + android_pixel_format format, const EGLint* attrib_list, + EGLint* colorSpace, + std::vector* strippedAttribList) { + for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) { + bool copyAttribute = true; + if (attr[0] == EGL_GL_COLORSPACE_KHR) { + // Fail immediately if the driver doesn't have color space support at all. + if (!dp->hasColorSpaceSupport) return false; + *colorSpace = attr[1]; + + // Strip the attribute if the driver doesn't understand it. + copyAttribute = false; + std::vector driverColorSpaces = getDriverColorSpaces(dp, format); + for (auto driverColorSpace : driverColorSpaces) { + if (attr[1] == driverColorSpace) { + copyAttribute = true; + break; + } + } + + // If the driver doesn't understand it, we should map sRGB-encoded P3 to + // sRGB rather than just dropping the colorspace on the floor. + // For this format, the driver is expected to apply the sRGB + // transfer function during framebuffer operations. + if (!copyAttribute && attr[1] == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) { + strippedAttribList->push_back(attr[0]); + strippedAttribList->push_back(EGL_GL_COLORSPACE_SRGB_KHR); + } + } + if (copyAttribute) { + strippedAttribList->push_back(attr[0]); + strippedAttribList->push_back(attr[1]); + } + } + // Terminate the attribute list. + strippedAttribList->push_back(EGL_NONE); + + // If the passed color space has wide color gamut, check whether the target native window + // supports wide color. + const bool colorSpaceIsNarrow = + *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || + *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || + *colorSpace == EGL_UNKNOWN; + if (window && !colorSpaceIsNarrow) { + bool windowSupportsWideColor = true; + // Ordinarily we'd put a call to native_window_get_wide_color_support + // at the beginning of the function so that we'll have the + // result when needed elsewhere in the function. + // However, because eglCreateWindowSurface is called by SurfaceFlinger and + // SurfaceFlinger is required to answer the call below we would + // end up in a deadlock situation. By moving the call to only happen + // if the application has specifically asked for wide-color we avoid + // the deadlock with SurfaceFlinger since it will not ask for a + // wide-color surface. + int err = native_window_get_wide_color_support(window, &windowSupportsWideColor); + + if (err) { + ALOGE("processAttributes: invalid window (win=%p) " + "failed (%#x) (already connected to another API?)", + window, err); + return false; + } + if (!windowSupportsWideColor) { + // Application has asked for a wide-color colorspace but + // wide-color support isn't available on the display the window is on. + return false; + } + } + return true; +} + +// Gets the native pixel format corrsponding to the passed EGLConfig. +void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, + android_pixel_format* format) { + // Set the native window's buffers format to match what this config requests. + // Whether to use sRGB gamma is not part of the EGLconfig, but is part + // of our native format. So if sRGB gamma is requested, we have to + // modify the EGLconfig's format before setting the native window's + // format. + + EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType); + + EGLint a = 0; + EGLint r, g, b; + r = g = b = 0; + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r); + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g); + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b); + cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a); + EGLint colorDepth = r + g + b; + + // Today, the driver only understands sRGB and linear on 888X + // formats. Strip other colorspaces from the attribute list and + // only use them to set the dataspace via + // native_window_set_buffers_dataspace + // if pixel format is RGBX 8888 + // TBD: Can test for future extensions that indicate that driver + // handles requested color space and we can let it through. + // allow SRGB and LINEAR. All others need to be stripped. + // else if 565, 4444 + // TBD: Can we assume these are supported if 8888 is? + // else if FP16 or 1010102 + // strip colorspace from attribs. + // endif + if (a == 0) { + if (colorDepth <= 16) { + *format = HAL_PIXEL_FORMAT_RGB_565; + } else { + if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { + if (colorDepth > 24) { + *format = HAL_PIXEL_FORMAT_RGBA_1010102; + } else { + *format = HAL_PIXEL_FORMAT_RGBX_8888; + } + } else { + *format = HAL_PIXEL_FORMAT_RGBA_FP16; + } + } + } else { + if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { + if (colorDepth > 24) { + *format = HAL_PIXEL_FORMAT_RGBA_1010102; + } else { + *format = HAL_PIXEL_FORMAT_RGBA_8888; + } + } else { + *format = HAL_PIXEL_FORMAT_RGBA_FP16; + } + } +} + +EGLBoolean sendSurfaceMetadata(egl_surface_t* s) { + android_smpte2086_metadata smpteMetadata; + if (s->getSmpte2086Metadata(smpteMetadata)) { + int err = + native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata); + s->resetSmpte2086Metadata(); + if (err != 0) { + ALOGE("error setting native window smpte2086 metadata: %s (%d)", + strerror(-err), err); + return EGL_FALSE; + } + } + android_cta861_3_metadata cta8613Metadata; + if (s->getCta8613Metadata(cta8613Metadata)) { + int err = + native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata); + s->resetCta8613Metadata(); + if (err != 0) { + ALOGE("error setting native window CTS 861.3 metadata: %s (%d)", + strerror(-err), err); + return EGL_FALSE; + } + } + return EGL_TRUE; +} + +EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, + NativeWindowType window, + const EGLint *attrib_list) +{ + const EGLint *origAttribList = attrib_list; + clearError(); + + egl_connection_t* cnx = nullptr; + egl_display_ptr dp = validate_display_connection(dpy, cnx); + if (dp) { + if (!window) { + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + int value = 0; + window->query(window, NATIVE_WINDOW_IS_VALID, &value); + if (!value) { + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + // NOTE: When using Vulkan backend, the Vulkan runtime makes all the + // native_window_* calls, so don't do them here. + if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { + int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); + if (result < 0) { + ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) " + "failed (%#x) (already connected to another API?)", + window, result); + return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + } + + EGLDisplay iDpy = dp->disp.dpy; + android_pixel_format format; + getNativePixelFormat(iDpy, cnx, config, &format); + + // now select correct colorspace and dataspace based on user's attribute list + EGLint colorSpace = EGL_UNKNOWN; + std::vector strippedAttribList; + if (!processAttributes(dp, window, format, attrib_list, &colorSpace, + &strippedAttribList)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + attrib_list = strippedAttribList.data(); + + if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { + int err = native_window_set_buffers_format(window, format); + if (err != 0) { + ALOGE("error setting native window pixel format: %s (%d)", + strerror(-err), err); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace); + if (dataSpace != HAL_DATASPACE_UNKNOWN) { + err = native_window_set_buffers_data_space(window, dataSpace); + if (err != 0) { + ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), + err); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + } + } + + // the EGL spec requires that a new EGLSurface default to swap interval + // 1, so explicitly set that on the window here. + ANativeWindow* anw = reinterpret_cast(window); + anw->setSwapInterval(anw, 1); + + EGLSurface surface = cnx->egl.eglCreateWindowSurface( + iDpy, config, window, attrib_list); + if (surface != EGL_NO_SURFACE) { + egl_surface_t* s = + new egl_surface_t(dp.get(), config, window, surface, + getReportedColorSpace(colorSpace), cnx); + return s; + } + + // EGLSurface creation failed + if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { + native_window_set_buffers_format(window, 0); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + } + } + return EGL_NO_SURFACE; +} + +EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, + NativePixmapType pixmap, + const EGLint *attrib_list) +{ + clearError(); + + egl_connection_t* cnx = nullptr; + egl_display_ptr dp = validate_display_connection(dpy, cnx); + if (dp) { + EGLDisplay iDpy = dp->disp.dpy; + android_pixel_format format; + getNativePixelFormat(iDpy, cnx, config, &format); + + // now select a corresponding sRGB format if needed + EGLint colorSpace = EGL_UNKNOWN; + std::vector strippedAttribList; + if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, + &strippedAttribList)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + attrib_list = strippedAttribList.data(); + + EGLSurface surface = cnx->egl.eglCreatePixmapSurface( + dp->disp.dpy, config, pixmap, attrib_list); + if (surface != EGL_NO_SURFACE) { + egl_surface_t* s = + new egl_surface_t(dp.get(), config, nullptr, surface, + getReportedColorSpace(colorSpace), cnx); + return s; + } + } + return EGL_NO_SURFACE; +} + +EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list) +{ + clearError(); + + egl_connection_t* cnx = nullptr; + egl_display_ptr dp = validate_display_connection(dpy, cnx); + if (dp) { + EGLDisplay iDpy = dp->disp.dpy; + android_pixel_format format; + getNativePixelFormat(iDpy, cnx, config, &format); + + // Select correct colorspace based on user's attribute list + EGLint colorSpace = EGL_UNKNOWN; + std::vector strippedAttribList; + if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, + &strippedAttribList)) { + ALOGE("error invalid colorspace: %d", colorSpace); + return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + attrib_list = strippedAttribList.data(); + + EGLSurface surface = cnx->egl.eglCreatePbufferSurface( + dp->disp.dpy, config, attrib_list); + if (surface != EGL_NO_SURFACE) { + egl_surface_t* s = + new egl_surface_t(dp.get(), config, nullptr, surface, + getReportedColorSpace(colorSpace), cnx); + return s; + } + } + return EGL_NO_SURFACE; +} + +EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t * const s = get_surface(surface); + EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface); + if (result == EGL_TRUE) { + _s.terminate(); + } + return result; +} + +EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t const * const s = get_surface(surface); + if (s->getColorSpaceAttribute(attribute, value)) { + return EGL_TRUE; + } else if (s->getSmpte2086Attribute(attribute, value)) { + return EGL_TRUE; + } else if (s->getCta8613Attribute(attribute, value)) { + return EGL_TRUE; + } + return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value); +} + +void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { + ATRACE_CALL(); + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + return; + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + setError(EGL_BAD_SURFACE, EGL_FALSE); + } +} + +// ---------------------------------------------------------------------------- +// Contexts +// ---------------------------------------------------------------------------- + +EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_list, const EGLint *attrib_list) +{ + clearError(); + + egl_connection_t* cnx = nullptr; + const egl_display_ptr dp = validate_display_connection(dpy, cnx); + if (dp) { + if (share_list != EGL_NO_CONTEXT) { + if (!ContextRef(dp.get(), share_list).get()) { + return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); + } + egl_context_t* const c = get_context(share_list); + share_list = c->context; + } + EGLContext context = cnx->egl.eglCreateContext( + dp->disp.dpy, config, share_list, attrib_list); + if (context != EGL_NO_CONTEXT) { + // figure out if it's a GLESv1 or GLESv2 + int version = 0; + if (attrib_list) { + while (*attrib_list != EGL_NONE) { + GLint attr = *attrib_list++; + GLint value = *attrib_list++; + if (attr == EGL_CONTEXT_CLIENT_VERSION) { + if (value == 1) { + version = egl_connection_t::GLESv1_INDEX; + } else if (value == 2 || value == 3) { + version = egl_connection_t::GLESv2_INDEX; + } + } + }; + } + egl_context_t* c = new egl_context_t(dpy, context, config, cnx, + version); + return c; + } + } + return EGL_NO_CONTEXT; +} + +EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) + return EGL_FALSE; + + ContextRef _c(dp.get(), ctx); + if (!_c.get()) + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); + + egl_context_t * const c = get_context(ctx); + EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context); + if (result == EGL_TRUE) { + _c.terminate(); + } + return result; +} + +EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx) +{ + clearError(); + + egl_display_ptr dp = validate_display(dpy); + if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + + // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not + // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is + // a valid but uninitialized display. + if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) || + (draw != EGL_NO_SURFACE) ) { + if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); + } + + // get a reference to the object passed in + ContextRef _c(dp.get(), ctx); + SurfaceRef _d(dp.get(), draw); + SurfaceRef _r(dp.get(), read); + + // validate the context (if not EGL_NO_CONTEXT) + if ((ctx != EGL_NO_CONTEXT) && !_c.get()) { + // EGL_NO_CONTEXT is valid + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); + } + + // these are the underlying implementation's object + EGLContext impl_ctx = EGL_NO_CONTEXT; + EGLSurface impl_draw = EGL_NO_SURFACE; + EGLSurface impl_read = EGL_NO_SURFACE; + + // these are our objects structs passed in + egl_context_t * c = nullptr; + egl_surface_t const * d = nullptr; + egl_surface_t const * r = nullptr; + + // these are the current objects structs + egl_context_t * cur_c = get_context(getContext()); + + if (ctx != EGL_NO_CONTEXT) { + c = get_context(ctx); + impl_ctx = c->context; + } else { + // no context given, use the implementation of the current context + if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) { + // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT); + return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE); + } + if (cur_c == nullptr) { + // no current context + // not an error, there is just no current context. + return EGL_TRUE; + } + } + + // retrieve the underlying implementation's draw EGLSurface + if (draw != EGL_NO_SURFACE) { + if (!_d.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + d = get_surface(draw); + impl_draw = d->surface; + } + + // retrieve the underlying implementation's read EGLSurface + if (read != EGL_NO_SURFACE) { + if (!_r.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + r = get_surface(read); + impl_read = r->surface; + } + + + EGLBoolean result = dp->makeCurrent(c, cur_c, + draw, read, ctx, + impl_draw, impl_read, impl_ctx); + + if (result == EGL_TRUE) { + if (c) { + setGLHooksThreadSpecific(c->cnx->hooks[c->version]); + egl_tls_t::setContext(ctx); + _c.acquire(); + _r.acquire(); + _d.acquire(); + } else { + setGLHooksThreadSpecific(&gHooksNoContext); + egl_tls_t::setContext(EGL_NO_CONTEXT); + } + } else { + // this will ALOGE the error + egl_connection_t* const cnx = &gEGLImpl; + result = setError(cnx->egl.eglGetError(), (EGLBoolean)EGL_FALSE); + } + return result; +} + + +EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + ContextRef _c(dp.get(), ctx); + if (!_c.get()) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); + + egl_context_t * const c = get_context(ctx); + return c->cnx->egl.eglQueryContext( + dp->disp.dpy, c->context, attribute, value); + +} + +EGLContext eglGetCurrentContext(void) +{ + // could be called before eglInitialize(), but we wouldn't have a context + // then, and this function would correctly return EGL_NO_CONTEXT. + + clearError(); + + EGLContext ctx = getContext(); + return ctx; +} + +EGLSurface eglGetCurrentSurface(EGLint readdraw) +{ + // could be called before eglInitialize(), but we wouldn't have a context + // then, and this function would correctly return EGL_NO_SURFACE. + + clearError(); + + EGLContext ctx = getContext(); + if (ctx) { + egl_context_t const * const c = get_context(ctx); + if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); + switch (readdraw) { + case EGL_READ: return c->read; + case EGL_DRAW: return c->draw; + default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + } + } + return EGL_NO_SURFACE; +} + +EGLDisplay eglGetCurrentDisplay(void) +{ + // could be called before eglInitialize(), but we wouldn't have a context + // then, and this function would correctly return EGL_NO_DISPLAY. + + clearError(); + + EGLContext ctx = getContext(); + if (ctx) { + egl_context_t const * const c = get_context(ctx); + if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); + return c->dpy; + } + return EGL_NO_DISPLAY; +} + +EGLBoolean eglWaitGL(void) +{ + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); + + return cnx->egl.eglWaitGL(); +} + +EGLBoolean eglWaitNative(EGLint engine) +{ + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); + + return cnx->egl.eglWaitNative(engine); +} + +EGLint eglGetError(void) +{ + EGLint err = EGL_SUCCESS; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + err = cnx->egl.eglGetError(); + } + if (err == EGL_SUCCESS) { + err = egl_tls_t::getError(); + } + return err; +} + +static __eglMustCastToProperFunctionPointerType findBuiltinWrapper( + const char* procname) { + const egl_connection_t* cnx = &gEGLImpl; + void* proc = nullptr; + + proc = dlsym(cnx->libEgl, procname); + if (proc) return (__eglMustCastToProperFunctionPointerType)proc; + + proc = dlsym(cnx->libGles2, procname); + if (proc) return (__eglMustCastToProperFunctionPointerType)proc; + + proc = dlsym(cnx->libGles1, procname); + if (proc) return (__eglMustCastToProperFunctionPointerType)proc; + + return nullptr; +} + +__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) +{ + // eglGetProcAddress() could be the very first function called + // in which case we must make sure we've initialized ourselves, this + // happens the first time egl_get_display() is called. + + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + setError(EGL_BAD_PARAMETER, NULL); + return nullptr; + } + + if (FILTER_EXTENSIONS(procname)) { + return nullptr; + } + + __eglMustCastToProperFunctionPointerType addr; + addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap)); + if (addr) return addr; + + addr = findBuiltinWrapper(procname); + if (addr) return addr; + + // this protects accesses to sGLExtentionMap and sGLExtentionSlot + pthread_mutex_lock(&sExtensionMapMutex); + + /* + * Since eglGetProcAddress() is not associated to anything, it needs + * to return a function pointer that "works" regardless of what + * the current context is. + * + * For this reason, we return a "forwarder", a small stub that takes + * care of calling the function associated with the context + * currently bound. + * + * We first look for extensions we've already resolved, if we're seeing + * this extension for the first time, we go through all our + * implementations and call eglGetProcAddress() and record the + * result in the appropriate implementation hooks and return the + * address of the forwarder corresponding to that hook set. + * + */ + + const std::string name(procname); + + auto& extentionMap = sGLExtentionMap; + auto pos = extentionMap.find(name); + addr = (pos != extentionMap.end()) ? pos->second : nullptr; + const int slot = sGLExtentionSlot; + + ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, + "no more slots for eglGetProcAddress(\"%s\")", + procname); + + if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { + bool found = false; + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetProcAddress) { + // Extensions are independent of the bound context + addr = + cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = + cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = + cnx->egl.eglGetProcAddress(procname); + if (addr) found = true; + } + + if (found) { + addr = gExtensionForwarders[slot]; + extentionMap[name] = addr; + sGLExtentionSlot++; + } + } + + pthread_mutex_unlock(&sExtensionMapMutex); + return addr; +} + +class FrameCompletionThread { +public: + + static void queueSync(EGLSyncKHR sync) { + static FrameCompletionThread thread; + + char name[64]; + + std::lock_guard lock(thread.mMutex); + snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued); + ATRACE_NAME(name); + + thread.mQueue.push_back(sync); + thread.mCondition.notify_one(); + thread.mFramesQueued++; + ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size())); + } + +private: + + FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) { + std::thread thread(&FrameCompletionThread::loop, this); + thread.detach(); + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-noreturn" + void loop() { + while (true) { + threadLoop(); + } + } +#pragma clang diagnostic pop + + void threadLoop() { + EGLSyncKHR sync; + uint32_t frameNum; + { + std::unique_lock lock(mMutex); + while (mQueue.empty()) { + mCondition.wait(lock); + } + sync = mQueue[0]; + frameNum = mFramesCompleted; + } + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + { + char name[64]; + snprintf(name, sizeof(name), "waiting for frame %u", (unsigned int)frameNum); + ATRACE_NAME(name); + + EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR); + if (result == EGL_FALSE) { + ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError()); + } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { + ALOGE("FrameCompletion: timeout waiting for fence"); + } + eglDestroySyncKHR(dpy, sync); + } + { + std::lock_guard lock(mMutex); + mQueue.pop_front(); + mFramesCompleted++; + ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); + } + } + + uint32_t mFramesQueued; + uint32_t mFramesCompleted; + std::deque mQueue; + std::condition_variable mCondition; + std::mutex mMutex; +}; + +EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, + EGLint *rects, EGLint n_rects) +{ + ATRACE_CALL(); + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), draw); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t* const s = get_surface(draw); + + if (CC_UNLIKELY(dp->traceGpuCompletion)) { + EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr); + if (sync != EGL_NO_SYNC_KHR) { + FrameCompletionThread::queueSync(sync); + } + } + + if (CC_UNLIKELY(dp->finishOnSwap)) { + uint32_t pixel; + egl_context_t * const c = get_context( egl_tls_t::getContext() ); + if (c) { + // glReadPixels() ensures that the frame is complete + s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1, + GL_RGBA,GL_UNSIGNED_BYTE,&pixel); + } + } + + if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { + if (!sendSurfaceMetadata(s)) { + native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL); + return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE); + } + } + + if (n_rects == 0) { + return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); + } + + std::vector androidRects((size_t)n_rects); + for (int r = 0; r < n_rects; ++r) { + int offset = r * 4; + int x = rects[offset]; + int y = rects[offset + 1]; + int width = rects[offset + 2]; + int height = rects[offset + 3]; + android_native_rect_t androidRect; + androidRect.left = x; + androidRect.top = y + height; + androidRect.right = x + width; + androidRect.bottom = y; + androidRects.push_back(androidRect); + } + if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { + native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), + androidRects.size()); + } + + if (s->cnx->egl.eglSwapBuffersWithDamageKHR) { + return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface, + rects, n_rects); + } else { + return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); + } +} + +EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0); +} + +EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, + NativePixmapType target) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t const * const s = get_surface(surface); + return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); +} + +const char* eglQueryString(EGLDisplay dpy, EGLint name) +{ + clearError(); + + // Generate an error quietly when client extensions (as defined by + // EGL_EXT_client_extensions) are queried. We do not want to rely on + // validate_display to generate the error as validate_display would log + // the error, which can be misleading. + // + // If we want to support EGL_EXT_client_extensions later, we can return + // the client extension string here instead. + if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) + return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return (const char *) nullptr; + + switch (name) { + case EGL_VENDOR: + return dp->getVendorString(); + case EGL_VERSION: + return dp->getVersionString(); + case EGL_EXTENSIONS: + return dp->getExtensionString(); + case EGL_CLIENT_APIS: + return dp->getClientApiString(); + default: + break; + } + return setError(EGL_BAD_PARAMETER, (const char *)nullptr); +} + +extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return (const char *) nullptr; + + switch (name) { + case EGL_VENDOR: + return dp->disp.queryString.vendor; + case EGL_VERSION: + return dp->disp.queryString.version; + case EGL_EXTENSIONS: + return dp->disp.queryString.extensions; + case EGL_CLIENT_APIS: + return dp->disp.queryString.clientApi; + default: + break; + } + return setError(EGL_BAD_PARAMETER, (const char *)nullptr); +} + +// ---------------------------------------------------------------------------- +// EGL 1.1 +// ---------------------------------------------------------------------------- + +EGLBoolean eglSurfaceAttrib( + EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t * const s = get_surface(surface); + + if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) { + if (!s->getNativeWindow()) { + setError(EGL_BAD_SURFACE, EGL_FALSE); + } + int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0); + return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + if (attribute == EGL_TIMESTAMPS_ANDROID) { + if (!s->getNativeWindow()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0); + return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + if (s->setSmpte2086Attribute(attribute, value)) { + return EGL_TRUE; + } else if (s->setCta8613Attribute(attribute, value)) { + return EGL_TRUE; + } else if (s->cnx->egl.eglSurfaceAttrib) { + return s->cnx->egl.eglSurfaceAttrib( + dp->disp.dpy, s->surface, attribute, value); + } + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); +} + +EGLBoolean eglBindTexImage( + EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t const * const s = get_surface(surface); + if (s->cnx->egl.eglBindTexImage) { + return s->cnx->egl.eglBindTexImage( + dp->disp.dpy, s->surface, buffer); + } + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); +} + +EGLBoolean eglReleaseTexImage( + EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t const * const s = get_surface(surface); + if (s->cnx->egl.eglReleaseTexImage) { + return s->cnx->egl.eglReleaseTexImage( + dp->disp.dpy, s->surface, buffer); + } + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); +} + +EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean res = EGL_TRUE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglSwapInterval) { + res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval); + } + + return res; +} + + +// ---------------------------------------------------------------------------- +// EGL 1.2 +// ---------------------------------------------------------------------------- + +EGLBoolean eglWaitClient(void) +{ + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); + + EGLBoolean res; + if (cnx->egl.eglWaitClient) { + res = cnx->egl.eglWaitClient(); + } else { + res = cnx->egl.eglWaitGL(); + } + return res; +} + +EGLBoolean eglBindAPI(EGLenum api) +{ + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + // bind this API on all EGLs + EGLBoolean res = EGL_TRUE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglBindAPI) { + res = cnx->egl.eglBindAPI(api); + } + return res; +} + +EGLenum eglQueryAPI(void) +{ + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryAPI) { + return cnx->egl.eglQueryAPI(); + } + + // or, it can only be OpenGL ES + return EGL_OPENGL_ES_API; +} + +EGLBoolean eglReleaseThread(void) +{ + clearError(); + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglReleaseThread) { + cnx->egl.eglReleaseThread(); + } + + // If there is context bound to the thread, release it + egl_display_t::loseCurrent(get_context(getContext())); + + egl_tls_t::clearTLS(); + return EGL_TRUE; +} + +EGLSurface eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list) +{ + clearError(); + + egl_connection_t* cnx = nullptr; + const egl_display_ptr dp = validate_display_connection(dpy, cnx); + if (!dp) return EGL_FALSE; + if (cnx->egl.eglCreatePbufferFromClientBuffer) { + return cnx->egl.eglCreatePbufferFromClientBuffer( + dp->disp.dpy, buftype, buffer, config, attrib_list); + } + return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); +} + +// ---------------------------------------------------------------------------- +// EGL_EGLEXT_VERSION 3 +// ---------------------------------------------------------------------------- + +EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, + const EGLint *attrib_list) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t const * const s = get_surface(surface); + if (s->cnx->egl.eglLockSurfaceKHR) { + return s->cnx->egl.eglLockSurfaceKHR( + dp->disp.dpy, s->surface, attrib_list); + } + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); +} + +EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + + egl_surface_t const * const s = get_surface(surface); + if (s->cnx->egl.eglUnlockSurfaceKHR) { + return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface); + } + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); +} + +EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attrib_list) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_IMAGE_KHR; + + ContextRef _c(dp.get(), ctx); + egl_context_t * const c = _c.get(); + + EGLImageKHR result = EGL_NO_IMAGE_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateImageKHR) { + result = cnx->egl.eglCreateImageKHR( + dp->disp.dpy, + c ? c->context : EGL_NO_CONTEXT, + target, buffer, attrib_list); + } + return result; +} + +EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglDestroyImageKHR) { + result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img); + } + return result; +} + +// ---------------------------------------------------------------------------- +// EGL_EGLEXT_VERSION 5 +// ---------------------------------------------------------------------------- + + +EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_SYNC_KHR; + + EGLSyncKHR result = EGL_NO_SYNC_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateSyncKHR) { + result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); + } + return result; +} + +EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglDestroySyncKHR) { + result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync); + } + return result; +} + +EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglSignalSyncKHR) { + result = cnx->egl.eglSignalSyncKHR( + dp->disp.dpy, sync, mode); + } + return result; +} + +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, + EGLint flags, EGLTimeKHR timeout) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLint result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) { + result = cnx->egl.eglClientWaitSyncKHR( + dp->disp.dpy, sync, flags, timeout); + } + return result; +} + +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, + EGLint attribute, EGLint *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) { + result = cnx->egl.eglGetSyncAttribKHR( + dp->disp.dpy, sync, attribute, value); + } + return result; +} + +EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_STREAM_KHR; + + EGLStreamKHR result = EGL_NO_STREAM_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateStreamKHR) { + result = cnx->egl.eglCreateStreamKHR( + dp->disp.dpy, attrib_list); + } + return result; +} + +EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglDestroyStreamKHR) { + result = cnx->egl.eglDestroyStreamKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamAttribKHR) { + result = cnx->egl.eglStreamAttribKHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLint *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryStreamKHR) { + result = cnx->egl.eglQueryStreamKHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLuint64KHR *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) { + result = cnx->egl.eglQueryStreamu64KHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, + EGLenum attribute, EGLTimeKHR *value) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) { + result = cnx->egl.eglQueryStreamTimeKHR( + dp->disp.dpy, stream, attribute, value); + } + return result; +} + +EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, + EGLStreamKHR stream, const EGLint *attrib_list) +{ + clearError(); + + egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_SURFACE; + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) { + EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR( + dp->disp.dpy, config, stream, attrib_list); + if (surface != EGL_NO_SURFACE) { + egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface, + EGL_GL_COLORSPACE_LINEAR_KHR, cnx); + return s; + } + } + return EGL_NO_SURFACE; +} + +EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, + EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { + result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, + EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { + result = cnx->egl.eglStreamConsumerAcquireKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, + EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { + result = cnx->egl.eglStreamConsumerReleaseKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( + EGLDisplay dpy, EGLStreamKHR stream) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; + + EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { + result = cnx->egl.eglGetStreamFileDescriptorKHR( + dp->disp.dpy, stream); + } + return result; +} + +EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( + EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_STREAM_KHR; + + EGLStreamKHR result = EGL_NO_STREAM_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) { + result = cnx->egl.eglCreateStreamFromFileDescriptorKHR( + dp->disp.dpy, file_descriptor); + } + return result; +} + +// ---------------------------------------------------------------------------- +// EGL_EGLEXT_VERSION 15 +// ---------------------------------------------------------------------------- + +EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { + clearError(); + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_FALSE; + EGLint result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglWaitSyncKHR) { + result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); + } + return result; +} + +// ---------------------------------------------------------------------------- +// ANDROID extensions +// ---------------------------------------------------------------------------- + +EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; + + EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { + result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); + } + return result; +} + +EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, + EGLnsecsANDROID time) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + return EGL_FALSE; + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + setError(EGL_BAD_SURFACE, EGL_FALSE); + return EGL_FALSE; + } + + egl_surface_t const * const s = get_surface(surface); + native_window_set_buffers_timestamp(s->getNativeWindow(), time); + + return EGL_TRUE; +} + +EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { + clearError(); + // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus + // this function cannot be implemented when this libEGL is built for + // vendors. +#ifndef __ANDROID_VNDK__ + if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); + return const_cast(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); +#else + return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); +#endif +} + +// ---------------------------------------------------------------------------- +// NVIDIA extensions +// ---------------------------------------------------------------------------- +EGLuint64NV eglGetSystemTimeFrequencyNV() +{ + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + + EGLuint64NV ret = 0; + egl_connection_t* const cnx = &gEGLImpl; + + if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { + return cnx->egl.eglGetSystemTimeFrequencyNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +EGLuint64NV eglGetSystemTimeNV() +{ + clearError(); + + if (egl_init_drivers() == EGL_FALSE) { + return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); + } + + EGLuint64NV ret = 0; + egl_connection_t* const cnx = &gEGLImpl; + + if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { + return cnx->egl.eglGetSystemTimeNV(); + } + + return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); +} + +// ---------------------------------------------------------------------------- +// Partial update extension +// ---------------------------------------------------------------------------- +EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, + EGLint *rects, EGLint n_rects) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + setError(EGL_BAD_DISPLAY, EGL_FALSE); + return EGL_FALSE; + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + setError(EGL_BAD_SURFACE, EGL_FALSE); + return EGL_FALSE; + } + + egl_surface_t const * const s = get_surface(surface); + if (s->cnx->egl.eglSetDamageRegionKHR) { + return s->cnx->egl.eglSetDamageRegionKHR(dp->disp.dpy, s->surface, + rects, n_rects); + } + + return EGL_FALSE; +} + +EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, + EGLuint64KHR *frameId) { + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + egl_surface_t const * const s = get_surface(surface); + + if (!s->getNativeWindow()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + uint64_t nextFrameId = 0; + int ret = native_window_get_next_frame_id(s->getNativeWindow(), &nextFrameId); + + if (ret != 0) { + // This should not happen. Return an error that is not in the spec + // so it's obvious something is very wrong. + ALOGE("eglGetNextFrameId: Unexpected error."); + return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); + } + + *frameId = nextFrameId; + return EGL_TRUE; +} + +EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, + EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + egl_surface_t const * const s = get_surface(surface); + + if (!s->getNativeWindow()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + nsecs_t* compositeDeadline = nullptr; + nsecs_t* compositeInterval = nullptr; + nsecs_t* compositeToPresentLatency = nullptr; + + for (int i = 0; i < numTimestamps; i++) { + switch (names[i]) { + case EGL_COMPOSITE_DEADLINE_ANDROID: + compositeDeadline = &values[i]; + break; + case EGL_COMPOSITE_INTERVAL_ANDROID: + compositeInterval = &values[i]; + break; + case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID: + compositeToPresentLatency = &values[i]; + break; + default: + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + } + + int ret = native_window_get_compositor_timing(s->getNativeWindow(), + compositeDeadline, compositeInterval, compositeToPresentLatency); + + switch (ret) { + case 0: + return EGL_TRUE; + case -ENOSYS: + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + default: + // This should not happen. Return an error that is not in the spec + // so it's obvious something is very wrong. + ALOGE("eglGetCompositorTiming: Unexpected error."); + return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); + } +} + +EGLBoolean eglGetCompositorTimingSupportedANDROID( + EGLDisplay dpy, EGLSurface surface, EGLint name) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + egl_surface_t const * const s = get_surface(surface); + + ANativeWindow* window = s->getNativeWindow(); + if (!window) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + switch (name) { + case EGL_COMPOSITE_DEADLINE_ANDROID: + case EGL_COMPOSITE_INTERVAL_ANDROID: + case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID: + return EGL_TRUE; + default: + return EGL_FALSE; + } +} + +EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, + EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, + EGLnsecsANDROID *values) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + egl_surface_t const * const s = get_surface(surface); + + if (!s->getNativeWindow()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + nsecs_t* requestedPresentTime = nullptr; + nsecs_t* acquireTime = nullptr; + nsecs_t* latchTime = nullptr; + nsecs_t* firstRefreshStartTime = nullptr; + nsecs_t* gpuCompositionDoneTime = nullptr; + nsecs_t* lastRefreshStartTime = nullptr; + nsecs_t* displayPresentTime = nullptr; + nsecs_t* dequeueReadyTime = nullptr; + nsecs_t* releaseTime = nullptr; + + for (int i = 0; i < numTimestamps; i++) { + switch (timestamps[i]) { + case EGL_REQUESTED_PRESENT_TIME_ANDROID: + requestedPresentTime = &values[i]; + break; + case EGL_RENDERING_COMPLETE_TIME_ANDROID: + acquireTime = &values[i]; + break; + case EGL_COMPOSITION_LATCH_TIME_ANDROID: + latchTime = &values[i]; + break; + case EGL_FIRST_COMPOSITION_START_TIME_ANDROID: + firstRefreshStartTime = &values[i]; + break; + case EGL_LAST_COMPOSITION_START_TIME_ANDROID: + lastRefreshStartTime = &values[i]; + break; + case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID: + gpuCompositionDoneTime = &values[i]; + break; + case EGL_DISPLAY_PRESENT_TIME_ANDROID: + displayPresentTime = &values[i]; + break; + case EGL_DEQUEUE_READY_TIME_ANDROID: + dequeueReadyTime = &values[i]; + break; + case EGL_READS_DONE_TIME_ANDROID: + releaseTime = &values[i]; + break; + default: + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + } + } + + int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId, + requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime, + lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime, + dequeueReadyTime, releaseTime); + + switch (ret) { + case 0: + return EGL_TRUE; + case -ENOENT: + return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE); + case -ENOSYS: + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + case -EINVAL: + return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); + default: + // This should not happen. Return an error that is not in the spec + // so it's obvious something is very wrong. + ALOGE("eglGetFrameTimestamps: Unexpected error."); + return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); + } +} + +EGLBoolean eglGetFrameTimestampSupportedANDROID( + EGLDisplay dpy, EGLSurface surface, EGLint timestamp) +{ + clearError(); + + const egl_display_ptr dp = validate_display(dpy); + if (!dp) { + return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); + } + + SurfaceRef _s(dp.get(), surface); + if (!_s.get()) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + egl_surface_t const * const s = get_surface(surface); + + ANativeWindow* window = s->getNativeWindow(); + if (!window) { + return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); + } + + switch (timestamp) { + case EGL_COMPOSITE_DEADLINE_ANDROID: + case EGL_COMPOSITE_INTERVAL_ANDROID: + case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID: + case EGL_REQUESTED_PRESENT_TIME_ANDROID: + case EGL_RENDERING_COMPLETE_TIME_ANDROID: + case EGL_COMPOSITION_LATCH_TIME_ANDROID: + case EGL_FIRST_COMPOSITION_START_TIME_ANDROID: + case EGL_LAST_COMPOSITION_START_TIME_ANDROID: + case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID: + case EGL_DEQUEUE_READY_TIME_ANDROID: + case EGL_READS_DONE_TIME_ANDROID: + return EGL_TRUE; + case EGL_DISPLAY_PRESENT_TIME_ANDROID: { + int value = 0; + window->query(window, + NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value); + return value == 0 ? EGL_FALSE : EGL_TRUE; + } + default: + return EGL_FALSE; + } +} diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp deleted file mode 100644 index d2dc514ff2..0000000000 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ /dev/null @@ -1,2445 +0,0 @@ -/* - ** Copyright 2007, 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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../egl_impl.h" - -#include "egl_display.h" -#include "egl_object.h" -#include "egl_tls.h" -#include "egl_trace.h" - -using namespace android; - -// ---------------------------------------------------------------------------- - -namespace android { - -using nsecs_t = int64_t; - -struct extention_map_t { - const char* name; - __eglMustCastToProperFunctionPointerType address; -}; - -/* - * This is the list of EGL extensions exposed to applications. - * - * Some of them (gBuiltinExtensionString) are implemented entirely in this EGL - * wrapper and are always available. - * - * The rest (gExtensionString) depend on support in the EGL driver, and are - * only available if the driver supports them. However, some of these must be - * supported because they are used by the Android system itself; these are - * listed as mandatory below and are required by the CDD. The system *assumes* - * the mandatory extensions are present and may not function properly if some - * are missing. - * - * NOTE: Both strings MUST have a single space as the last character. - */ - -extern char const * const gBuiltinExtensionString; -extern char const * const gExtensionString; - -// clang-format off -// Extensions implemented by the EGL wrapper. -char const * const gBuiltinExtensionString = - "EGL_KHR_get_all_proc_addresses " - "EGL_ANDROID_presentation_time " - "EGL_KHR_swap_buffers_with_damage " - "EGL_ANDROID_get_native_client_buffer " - "EGL_ANDROID_front_buffer_auto_refresh " - "EGL_ANDROID_get_frame_timestamps " - "EGL_EXT_surface_SMPTE2086_metadata " - "EGL_EXT_surface_CTA861_3_metadata " - ; - -// Whitelist of extensions exposed to applications if implemented in the vendor driver. -char const * const gExtensionString = - "EGL_KHR_image " // mandatory - "EGL_KHR_image_base " // mandatory - "EGL_EXT_image_gl_colorspace " - "EGL_KHR_image_pixmap " - "EGL_KHR_lock_surface " - "EGL_KHR_gl_colorspace " - "EGL_KHR_gl_texture_2D_image " - "EGL_KHR_gl_texture_3D_image " - "EGL_KHR_gl_texture_cubemap_image " - "EGL_KHR_gl_renderbuffer_image " - "EGL_KHR_reusable_sync " - "EGL_KHR_fence_sync " - "EGL_KHR_create_context " - "EGL_KHR_config_attribs " - "EGL_KHR_surfaceless_context " - "EGL_KHR_stream " - "EGL_KHR_stream_fifo " - "EGL_KHR_stream_producer_eglsurface " - "EGL_KHR_stream_consumer_gltexture " - "EGL_KHR_stream_cross_process_fd " - "EGL_EXT_create_context_robustness " - "EGL_NV_system_time " - "EGL_ANDROID_image_native_buffer " // mandatory - "EGL_KHR_wait_sync " // strongly recommended - "EGL_ANDROID_recordable " // mandatory - "EGL_KHR_partial_update " // strongly recommended - "EGL_EXT_pixel_format_float " - "EGL_EXT_buffer_age " // strongly recommended with partial_update - "EGL_KHR_create_context_no_error " - "EGL_KHR_mutable_render_buffer " - "EGL_EXT_yuv_surface " - "EGL_EXT_protected_content " - "EGL_IMG_context_priority " - "EGL_KHR_no_config_context " - ; -// clang-format on - -// extensions not exposed to applications but used by the ANDROID system -// "EGL_ANDROID_blob_cache " // strongly recommended -// "EGL_IMG_hibernate_process " // optional -// "EGL_ANDROID_native_fence_sync " // strongly recommended -// "EGL_ANDROID_framebuffer_target " // mandatory for HWC 1.1 - -/* - * EGL Extensions entry-points exposed to 3rd party applications - * (keep in sync with gExtensionString above) - * - */ -static const extention_map_t sExtensionMap[] = { - // EGL_KHR_lock_surface - { "eglLockSurfaceKHR", - (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR }, - { "eglUnlockSurfaceKHR", - (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR }, - - // EGL_KHR_image, EGL_KHR_image_base - { "eglCreateImageKHR", - (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, - { "eglDestroyImageKHR", - (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, - - // EGL_KHR_reusable_sync, EGL_KHR_fence_sync - { "eglCreateSyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR }, - { "eglDestroySyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR }, - { "eglClientWaitSyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR }, - { "eglSignalSyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglSignalSyncKHR }, - { "eglGetSyncAttribKHR", - (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR }, - - // EGL_NV_system_time - { "eglGetSystemTimeFrequencyNV", - (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV }, - { "eglGetSystemTimeNV", - (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV }, - - // EGL_KHR_wait_sync - { "eglWaitSyncKHR", - (__eglMustCastToProperFunctionPointerType)&eglWaitSyncKHR }, - - // EGL_ANDROID_presentation_time - { "eglPresentationTimeANDROID", - (__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID }, - - // EGL_KHR_swap_buffers_with_damage - { "eglSwapBuffersWithDamageKHR", - (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR }, - - // EGL_ANDROID_get_native_client_buffer - { "eglGetNativeClientBufferANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetNativeClientBufferANDROID }, - - // EGL_KHR_partial_update - { "eglSetDamageRegionKHR", - (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR }, - - { "eglCreateStreamKHR", - (__eglMustCastToProperFunctionPointerType)&eglCreateStreamKHR }, - { "eglDestroyStreamKHR", - (__eglMustCastToProperFunctionPointerType)&eglDestroyStreamKHR }, - { "eglStreamAttribKHR", - (__eglMustCastToProperFunctionPointerType)&eglStreamAttribKHR }, - { "eglQueryStreamKHR", - (__eglMustCastToProperFunctionPointerType)&eglQueryStreamKHR }, - { "eglQueryStreamu64KHR", - (__eglMustCastToProperFunctionPointerType)&eglQueryStreamu64KHR }, - { "eglQueryStreamTimeKHR", - (__eglMustCastToProperFunctionPointerType)&eglQueryStreamTimeKHR }, - { "eglCreateStreamProducerSurfaceKHR", - (__eglMustCastToProperFunctionPointerType)&eglCreateStreamProducerSurfaceKHR }, - { "eglStreamConsumerGLTextureExternalKHR", - (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerGLTextureExternalKHR }, - { "eglStreamConsumerAcquireKHR", - (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerAcquireKHR }, - { "eglStreamConsumerReleaseKHR", - (__eglMustCastToProperFunctionPointerType)&eglStreamConsumerReleaseKHR }, - { "eglGetStreamFileDescriptorKHR", - (__eglMustCastToProperFunctionPointerType)&eglGetStreamFileDescriptorKHR }, - { "eglCreateStreamFromFileDescriptorKHR", - (__eglMustCastToProperFunctionPointerType)&eglCreateStreamFromFileDescriptorKHR }, - - // EGL_ANDROID_get_frame_timestamps - { "eglGetNextFrameIdANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetNextFrameIdANDROID }, - { "eglGetCompositorTimingANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingANDROID }, - { "eglGetCompositorTimingSupportedANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetCompositorTimingSupportedANDROID }, - { "eglGetFrameTimestampsANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampsANDROID }, - { "eglGetFrameTimestampSupportedANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetFrameTimestampSupportedANDROID }, - - // EGL_ANDROID_native_fence_sync - { "eglDupNativeFenceFDANDROID", - (__eglMustCastToProperFunctionPointerType)&eglDupNativeFenceFDANDROID }, -}; - -/* - * These extensions entry-points should not be exposed to applications. - * They're used internally by the Android EGL layer. - */ -#define FILTER_EXTENSIONS(procname) \ - (!strcmp((procname), "eglSetBlobCacheFuncsANDROID") || \ - !strcmp((procname), "eglHibernateProcessIMG") || \ - !strcmp((procname), "eglAwakenProcessIMG")) - -// accesses protected by sExtensionMapMutex -static std::unordered_map sGLExtentionMap; - -static int sGLExtentionSlot = 0; -static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; - -static void(*findProcAddress(const char* name, - const extention_map_t* map, size_t n))() { - for (uint32_t i=0 ; i(display); - if (index >= NUM_DISPLAYS) { - return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); - } - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY); - } - - EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display); - return dpy; -} - -// ---------------------------------------------------------------------------- -// Initialization -// ---------------------------------------------------------------------------- - -EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) -{ - clearError(); - - egl_display_ptr dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - - EGLBoolean res = dp->initialize(major, minor); - - return res; -} - -EGLBoolean eglTerminate(EGLDisplay dpy) -{ - // NOTE: don't unload the drivers b/c some APIs can be called - // after eglTerminate() has been called. eglTerminate() only - // terminates an EGLDisplay, not a EGL itself. - - clearError(); - - egl_display_ptr dp = get_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - - EGLBoolean res = dp->terminate(); - - return res; -} - -// ---------------------------------------------------------------------------- -// configuration -// ---------------------------------------------------------------------------- - -EGLBoolean eglGetConfigs( EGLDisplay dpy, - EGLConfig *configs, - EGLint config_size, EGLint *num_config) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - if (num_config==nullptr) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - EGLBoolean res = EGL_FALSE; - *num_config = 0; - - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso) { - res = cnx->egl.eglGetConfigs( - dp->disp.dpy, configs, config_size, num_config); - } - - return res; -} - -EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, - EGLConfig *configs, EGLint config_size, - EGLint *num_config) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - if (num_config==nullptr) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - EGLBoolean res = EGL_FALSE; - *num_config = 0; - - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso) { - if (attrib_list) { - char value[PROPERTY_VALUE_MAX]; - property_get("debug.egl.force_msaa", value, "false"); - - if (!strcmp(value, "true")) { - size_t attribCount = 0; - EGLint attrib = attrib_list[0]; - - // Only enable MSAA if the context is OpenGL ES 2.0 and - // if no caveat is requested - const EGLint *attribRendererable = nullptr; - const EGLint *attribCaveat = nullptr; - - // Count the number of attributes and look for - // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT - while (attrib != EGL_NONE) { - attrib = attrib_list[attribCount]; - switch (attrib) { - case EGL_RENDERABLE_TYPE: - attribRendererable = &attrib_list[attribCount]; - break; - case EGL_CONFIG_CAVEAT: - attribCaveat = &attrib_list[attribCount]; - break; - default: - break; - } - attribCount++; - } - - if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT && - (!attribCaveat || attribCaveat[1] != EGL_NONE)) { - - // Insert 2 extra attributes to force-enable MSAA 4x - EGLint aaAttribs[attribCount + 4]; - aaAttribs[0] = EGL_SAMPLE_BUFFERS; - aaAttribs[1] = 1; - aaAttribs[2] = EGL_SAMPLES; - aaAttribs[3] = 4; - - memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint)); - - EGLint numConfigAA; - EGLBoolean resAA = cnx->egl.eglChooseConfig( - dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA); - - if (resAA == EGL_TRUE && numConfigAA > 0) { - ALOGD("Enabling MSAA 4x"); - *num_config = numConfigAA; - return resAA; - } - } - } - } - - res = cnx->egl.eglChooseConfig( - dp->disp.dpy, attrib_list, configs, config_size, num_config); - } - return res; -} - -EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, - EGLint attribute, EGLint *value) -{ - clearError(); - - egl_connection_t* cnx = nullptr; - const egl_display_ptr dp = validate_display_connection(dpy, cnx); - if (!dp) return EGL_FALSE; - - return cnx->egl.eglGetConfigAttrib( - dp->disp.dpy, config, attribute, value); -} - -// ---------------------------------------------------------------------------- -// surfaces -// ---------------------------------------------------------------------------- - -// Translates EGL color spaces to Android data spaces. -static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { - if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { - return HAL_DATASPACE_UNKNOWN; - } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { - return HAL_DATASPACE_SRGB; - } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) { - return HAL_DATASPACE_DISPLAY_P3; - } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT) { - return HAL_DATASPACE_DISPLAY_P3_LINEAR; - } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_EXT) { - return HAL_DATASPACE_V0_SCRGB; - } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) { - return HAL_DATASPACE_V0_SCRGB_LINEAR; - } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) { - return HAL_DATASPACE_BT2020_LINEAR; - } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) { - return HAL_DATASPACE_BT2020_PQ; - } - return HAL_DATASPACE_UNKNOWN; -} - -// Get the colorspace value that should be reported from queries. When the colorspace -// is unknown (no attribute passed), default to reporting LINEAR. -static EGLint getReportedColorSpace(EGLint colorspace) { - return colorspace == EGL_UNKNOWN ? EGL_GL_COLORSPACE_LINEAR_KHR : colorspace; -} - -// Returns a list of color spaces understood by the vendor EGL driver. -static std::vector getDriverColorSpaces(egl_display_ptr dp, - android_pixel_format format) { - std::vector colorSpaces; - if (!dp->hasColorSpaceSupport) return colorSpaces; - - // OpenGL drivers only support sRGB encoding with 8-bit formats. - // RGB_888 is never returned by getNativePixelFormat, but is included for completeness. - const bool formatSupportsSRGBEncoding = - format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 || - format == HAL_PIXEL_FORMAT_RGB_888; - const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16; - - if (formatSupportsSRGBEncoding) { - // sRGB and linear are always supported when color space support is present. - colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); - colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); - // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats. - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_display_p3")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); - } - } - - // According to the spec, scRGB is only supported for floating point formats. - // For non-linear scRGB, the application is responsible for applying the - // transfer function. - if (formatIsFloatingPoint) { - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_scrgb")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT); - } - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_scrgb_linear")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); - } - } - - // BT2020 can be used with any pixel format. PQ encoding must be applied by the - // application and does not affect the behavior of OpenGL. - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_bt2020_linear")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT); - } - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_bt2020_pq")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); - } - - // Linear DCI-P3 simply uses different primaries than standard RGB and thus - // can be used with any pixel format. - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_display_p3_linear")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); - } - return colorSpaces; -} - -// Cleans up color space related parameters that the driver does not understand. -// If there is no color space attribute in attrib_list, colorSpace is left -// unmodified. -static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, - android_pixel_format format, const EGLint* attrib_list, - EGLint* colorSpace, - std::vector* strippedAttribList) { - for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) { - bool copyAttribute = true; - if (attr[0] == EGL_GL_COLORSPACE_KHR) { - // Fail immediately if the driver doesn't have color space support at all. - if (!dp->hasColorSpaceSupport) return false; - *colorSpace = attr[1]; - - // Strip the attribute if the driver doesn't understand it. - copyAttribute = false; - std::vector driverColorSpaces = getDriverColorSpaces(dp, format); - for (auto driverColorSpace : driverColorSpaces) { - if (attr[1] == driverColorSpace) { - copyAttribute = true; - break; - } - } - - // If the driver doesn't understand it, we should map sRGB-encoded P3 to - // sRGB rather than just dropping the colorspace on the floor. - // For this format, the driver is expected to apply the sRGB - // transfer function during framebuffer operations. - if (!copyAttribute && attr[1] == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) { - strippedAttribList->push_back(attr[0]); - strippedAttribList->push_back(EGL_GL_COLORSPACE_SRGB_KHR); - } - } - if (copyAttribute) { - strippedAttribList->push_back(attr[0]); - strippedAttribList->push_back(attr[1]); - } - } - // Terminate the attribute list. - strippedAttribList->push_back(EGL_NONE); - - // If the passed color space has wide color gamut, check whether the target native window - // supports wide color. - const bool colorSpaceIsNarrow = - *colorSpace == EGL_GL_COLORSPACE_SRGB_KHR || - *colorSpace == EGL_GL_COLORSPACE_LINEAR_KHR || - *colorSpace == EGL_UNKNOWN; - if (window && !colorSpaceIsNarrow) { - bool windowSupportsWideColor = true; - // Ordinarily we'd put a call to native_window_get_wide_color_support - // at the beginning of the function so that we'll have the - // result when needed elsewhere in the function. - // However, because eglCreateWindowSurface is called by SurfaceFlinger and - // SurfaceFlinger is required to answer the call below we would - // end up in a deadlock situation. By moving the call to only happen - // if the application has specifically asked for wide-color we avoid - // the deadlock with SurfaceFlinger since it will not ask for a - // wide-color surface. - int err = native_window_get_wide_color_support(window, &windowSupportsWideColor); - - if (err) { - ALOGE("processAttributes: invalid window (win=%p) " - "failed (%#x) (already connected to another API?)", - window, err); - return false; - } - if (!windowSupportsWideColor) { - // Application has asked for a wide-color colorspace but - // wide-color support isn't available on the display the window is on. - return false; - } - } - return true; -} - -// Gets the native pixel format corrsponding to the passed EGLConfig. -void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, - android_pixel_format* format) { - // Set the native window's buffers format to match what this config requests. - // Whether to use sRGB gamma is not part of the EGLconfig, but is part - // of our native format. So if sRGB gamma is requested, we have to - // modify the EGLconfig's format before setting the native window's - // format. - - EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; - cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType); - - EGLint a = 0; - EGLint r, g, b; - r = g = b = 0; - cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r); - cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g); - cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b); - cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a); - EGLint colorDepth = r + g + b; - - // Today, the driver only understands sRGB and linear on 888X - // formats. Strip other colorspaces from the attribute list and - // only use them to set the dataspace via - // native_window_set_buffers_dataspace - // if pixel format is RGBX 8888 - // TBD: Can test for future extensions that indicate that driver - // handles requested color space and we can let it through. - // allow SRGB and LINEAR. All others need to be stripped. - // else if 565, 4444 - // TBD: Can we assume these are supported if 8888 is? - // else if FP16 or 1010102 - // strip colorspace from attribs. - // endif - if (a == 0) { - if (colorDepth <= 16) { - *format = HAL_PIXEL_FORMAT_RGB_565; - } else { - if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { - if (colorDepth > 24) { - *format = HAL_PIXEL_FORMAT_RGBA_1010102; - } else { - *format = HAL_PIXEL_FORMAT_RGBX_8888; - } - } else { - *format = HAL_PIXEL_FORMAT_RGBA_FP16; - } - } - } else { - if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) { - if (colorDepth > 24) { - *format = HAL_PIXEL_FORMAT_RGBA_1010102; - } else { - *format = HAL_PIXEL_FORMAT_RGBA_8888; - } - } else { - *format = HAL_PIXEL_FORMAT_RGBA_FP16; - } - } -} - -EGLBoolean sendSurfaceMetadata(egl_surface_t* s) { - android_smpte2086_metadata smpteMetadata; - if (s->getSmpte2086Metadata(smpteMetadata)) { - int err = - native_window_set_buffers_smpte2086_metadata(s->getNativeWindow(), &smpteMetadata); - s->resetSmpte2086Metadata(); - if (err != 0) { - ALOGE("error setting native window smpte2086 metadata: %s (%d)", - strerror(-err), err); - return EGL_FALSE; - } - } - android_cta861_3_metadata cta8613Metadata; - if (s->getCta8613Metadata(cta8613Metadata)) { - int err = - native_window_set_buffers_cta861_3_metadata(s->getNativeWindow(), &cta8613Metadata); - s->resetCta8613Metadata(); - if (err != 0) { - ALOGE("error setting native window CTS 861.3 metadata: %s (%d)", - strerror(-err), err); - return EGL_FALSE; - } - } - return EGL_TRUE; -} - -EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, - NativeWindowType window, - const EGLint *attrib_list) -{ - const EGLint *origAttribList = attrib_list; - clearError(); - - egl_connection_t* cnx = nullptr; - egl_display_ptr dp = validate_display_connection(dpy, cnx); - if (dp) { - if (!window) { - return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } - - int value = 0; - window->query(window, NATIVE_WINDOW_IS_VALID, &value); - if (!value) { - return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } - - // NOTE: When using Vulkan backend, the Vulkan runtime makes all the - // native_window_* calls, so don't do them here. - if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { - int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); - if (result < 0) { - ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) " - "failed (%#x) (already connected to another API?)", - window, result); - return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE); - } - } - - EGLDisplay iDpy = dp->disp.dpy; - android_pixel_format format; - getNativePixelFormat(iDpy, cnx, config, &format); - - // now select correct colorspace and dataspace based on user's attribute list - EGLint colorSpace = EGL_UNKNOWN; - std::vector strippedAttribList; - if (!processAttributes(dp, window, format, attrib_list, &colorSpace, - &strippedAttribList)) { - ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); - } - attrib_list = strippedAttribList.data(); - - if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { - int err = native_window_set_buffers_format(window, format); - if (err != 0) { - ALOGE("error setting native window pixel format: %s (%d)", - strerror(-err), err); - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } - - android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace); - if (dataSpace != HAL_DATASPACE_UNKNOWN) { - err = native_window_set_buffers_data_space(window, dataSpace); - if (err != 0) { - ALOGE("error setting native window pixel dataSpace: %s (%d)", strerror(-err), - err); - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } - } - } - - // the EGL spec requires that a new EGLSurface default to swap interval - // 1, so explicitly set that on the window here. - ANativeWindow* anw = reinterpret_cast(window); - anw->setSwapInterval(anw, 1); - - EGLSurface surface = cnx->egl.eglCreateWindowSurface( - iDpy, config, window, attrib_list); - if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = - new egl_surface_t(dp.get(), config, window, surface, - getReportedColorSpace(colorSpace), cnx); - return s; - } - - // EGLSurface creation failed - if (cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { - native_window_set_buffers_format(window, 0); - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - } - } - return EGL_NO_SURFACE; -} - -EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, - NativePixmapType pixmap, - const EGLint *attrib_list) -{ - clearError(); - - egl_connection_t* cnx = nullptr; - egl_display_ptr dp = validate_display_connection(dpy, cnx); - if (dp) { - EGLDisplay iDpy = dp->disp.dpy; - android_pixel_format format; - getNativePixelFormat(iDpy, cnx, config, &format); - - // now select a corresponding sRGB format if needed - EGLint colorSpace = EGL_UNKNOWN; - std::vector strippedAttribList; - if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, - &strippedAttribList)) { - ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); - } - attrib_list = strippedAttribList.data(); - - EGLSurface surface = cnx->egl.eglCreatePixmapSurface( - dp->disp.dpy, config, pixmap, attrib_list); - if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = - new egl_surface_t(dp.get(), config, nullptr, surface, - getReportedColorSpace(colorSpace), cnx); - return s; - } - } - return EGL_NO_SURFACE; -} - -EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, - const EGLint *attrib_list) -{ - clearError(); - - egl_connection_t* cnx = nullptr; - egl_display_ptr dp = validate_display_connection(dpy, cnx); - if (dp) { - EGLDisplay iDpy = dp->disp.dpy; - android_pixel_format format; - getNativePixelFormat(iDpy, cnx, config, &format); - - // Select correct colorspace based on user's attribute list - EGLint colorSpace = EGL_UNKNOWN; - std::vector strippedAttribList; - if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, - &strippedAttribList)) { - ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); - } - attrib_list = strippedAttribList.data(); - - EGLSurface surface = cnx->egl.eglCreatePbufferSurface( - dp->disp.dpy, config, attrib_list); - if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = - new egl_surface_t(dp.get(), config, nullptr, surface, - getReportedColorSpace(colorSpace), cnx); - return s; - } - } - return EGL_NO_SURFACE; -} - -EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t * const s = get_surface(surface); - EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface); - if (result == EGL_TRUE) { - _s.terminate(); - } - return result; -} - -EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, - EGLint attribute, EGLint *value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t const * const s = get_surface(surface); - if (s->getColorSpaceAttribute(attribute, value)) { - return EGL_TRUE; - } else if (s->getSmpte2086Attribute(attribute, value)) { - return EGL_TRUE; - } else if (s->getCta8613Attribute(attribute, value)) { - return EGL_TRUE; - } - return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value); -} - -void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { - ATRACE_CALL(); - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - return; - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - setError(EGL_BAD_SURFACE, EGL_FALSE); - } -} - -// ---------------------------------------------------------------------------- -// Contexts -// ---------------------------------------------------------------------------- - -EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, - EGLContext share_list, const EGLint *attrib_list) -{ - clearError(); - - egl_connection_t* cnx = nullptr; - const egl_display_ptr dp = validate_display_connection(dpy, cnx); - if (dp) { - if (share_list != EGL_NO_CONTEXT) { - if (!ContextRef(dp.get(), share_list).get()) { - return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); - } - egl_context_t* const c = get_context(share_list); - share_list = c->context; - } - EGLContext context = cnx->egl.eglCreateContext( - dp->disp.dpy, config, share_list, attrib_list); - if (context != EGL_NO_CONTEXT) { - // figure out if it's a GLESv1 or GLESv2 - int version = 0; - if (attrib_list) { - while (*attrib_list != EGL_NONE) { - GLint attr = *attrib_list++; - GLint value = *attrib_list++; - if (attr == EGL_CONTEXT_CLIENT_VERSION) { - if (value == 1) { - version = egl_connection_t::GLESv1_INDEX; - } else if (value == 2 || value == 3) { - version = egl_connection_t::GLESv2_INDEX; - } - } - }; - } - egl_context_t* c = new egl_context_t(dpy, context, config, cnx, - version); - return c; - } - } - return EGL_NO_CONTEXT; -} - -EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) - return EGL_FALSE; - - ContextRef _c(dp.get(), ctx); - if (!_c.get()) - return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); - - egl_context_t * const c = get_context(ctx); - EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context); - if (result == EGL_TRUE) { - _c.terminate(); - } - return result; -} - -EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, - EGLSurface read, EGLContext ctx) -{ - clearError(); - - egl_display_ptr dp = validate_display(dpy); - if (!dp) return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - - // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not - // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is - // a valid but uninitialized display. - if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) || - (draw != EGL_NO_SURFACE) ) { - if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); - } - - // get a reference to the object passed in - ContextRef _c(dp.get(), ctx); - SurfaceRef _d(dp.get(), draw); - SurfaceRef _r(dp.get(), read); - - // validate the context (if not EGL_NO_CONTEXT) - if ((ctx != EGL_NO_CONTEXT) && !_c.get()) { - // EGL_NO_CONTEXT is valid - return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); - } - - // these are the underlying implementation's object - EGLContext impl_ctx = EGL_NO_CONTEXT; - EGLSurface impl_draw = EGL_NO_SURFACE; - EGLSurface impl_read = EGL_NO_SURFACE; - - // these are our objects structs passed in - egl_context_t * c = nullptr; - egl_surface_t const * d = nullptr; - egl_surface_t const * r = nullptr; - - // these are the current objects structs - egl_context_t * cur_c = get_context(getContext()); - - if (ctx != EGL_NO_CONTEXT) { - c = get_context(ctx); - impl_ctx = c->context; - } else { - // no context given, use the implementation of the current context - if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) { - // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT); - return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE); - } - if (cur_c == nullptr) { - // no current context - // not an error, there is just no current context. - return EGL_TRUE; - } - } - - // retrieve the underlying implementation's draw EGLSurface - if (draw != EGL_NO_SURFACE) { - if (!_d.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - d = get_surface(draw); - impl_draw = d->surface; - } - - // retrieve the underlying implementation's read EGLSurface - if (read != EGL_NO_SURFACE) { - if (!_r.get()) return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - r = get_surface(read); - impl_read = r->surface; - } - - - EGLBoolean result = dp->makeCurrent(c, cur_c, - draw, read, ctx, - impl_draw, impl_read, impl_ctx); - - if (result == EGL_TRUE) { - if (c) { - setGLHooksThreadSpecific(c->cnx->hooks[c->version]); - egl_tls_t::setContext(ctx); - _c.acquire(); - _r.acquire(); - _d.acquire(); - } else { - setGLHooksThreadSpecific(&gHooksNoContext); - egl_tls_t::setContext(EGL_NO_CONTEXT); - } - } else { - // this will ALOGE the error - egl_connection_t* const cnx = &gEGLImpl; - result = setError(cnx->egl.eglGetError(), (EGLBoolean)EGL_FALSE); - } - return result; -} - - -EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, - EGLint attribute, EGLint *value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - ContextRef _c(dp.get(), ctx); - if (!_c.get()) return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); - - egl_context_t * const c = get_context(ctx); - return c->cnx->egl.eglQueryContext( - dp->disp.dpy, c->context, attribute, value); - -} - -EGLContext eglGetCurrentContext(void) -{ - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would correctly return EGL_NO_CONTEXT. - - clearError(); - - EGLContext ctx = getContext(); - return ctx; -} - -EGLSurface eglGetCurrentSurface(EGLint readdraw) -{ - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would correctly return EGL_NO_SURFACE. - - clearError(); - - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); - switch (readdraw) { - case EGL_READ: return c->read; - case EGL_DRAW: return c->draw; - default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE); - } - } - return EGL_NO_SURFACE; -} - -EGLDisplay eglGetCurrentDisplay(void) -{ - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would correctly return EGL_NO_DISPLAY. - - clearError(); - - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE); - return c->dpy; - } - return EGL_NO_DISPLAY; -} - -EGLBoolean eglWaitGL(void) -{ - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); - - return cnx->egl.eglWaitGL(); -} - -EGLBoolean eglWaitNative(EGLint engine) -{ - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); - - return cnx->egl.eglWaitNative(engine); -} - -EGLint eglGetError(void) -{ - EGLint err = EGL_SUCCESS; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso) { - err = cnx->egl.eglGetError(); - } - if (err == EGL_SUCCESS) { - err = egl_tls_t::getError(); - } - return err; -} - -static __eglMustCastToProperFunctionPointerType findBuiltinWrapper( - const char* procname) { - const egl_connection_t* cnx = &gEGLImpl; - void* proc = nullptr; - - proc = dlsym(cnx->libEgl, procname); - if (proc) return (__eglMustCastToProperFunctionPointerType)proc; - - proc = dlsym(cnx->libGles2, procname); - if (proc) return (__eglMustCastToProperFunctionPointerType)proc; - - proc = dlsym(cnx->libGles1, procname); - if (proc) return (__eglMustCastToProperFunctionPointerType)proc; - - return nullptr; -} - -__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) -{ - // eglGetProcAddress() could be the very first function called - // in which case we must make sure we've initialized ourselves, this - // happens the first time egl_get_display() is called. - - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - setError(EGL_BAD_PARAMETER, NULL); - return nullptr; - } - - if (FILTER_EXTENSIONS(procname)) { - return nullptr; - } - - __eglMustCastToProperFunctionPointerType addr; - addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap)); - if (addr) return addr; - - addr = findBuiltinWrapper(procname); - if (addr) return addr; - - // this protects accesses to sGLExtentionMap and sGLExtentionSlot - pthread_mutex_lock(&sExtensionMapMutex); - - /* - * Since eglGetProcAddress() is not associated to anything, it needs - * to return a function pointer that "works" regardless of what - * the current context is. - * - * For this reason, we return a "forwarder", a small stub that takes - * care of calling the function associated with the context - * currently bound. - * - * We first look for extensions we've already resolved, if we're seeing - * this extension for the first time, we go through all our - * implementations and call eglGetProcAddress() and record the - * result in the appropriate implementation hooks and return the - * address of the forwarder corresponding to that hook set. - * - */ - - const std::string name(procname); - - auto& extentionMap = sGLExtentionMap; - auto pos = extentionMap.find(name); - addr = (pos != extentionMap.end()) ? pos->second : nullptr; - const int slot = sGLExtentionSlot; - - ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, - "no more slots for eglGetProcAddress(\"%s\")", - procname); - - if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { - bool found = false; - - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglGetProcAddress) { - // Extensions are independent of the bound context - addr = - cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = - cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = - cnx->egl.eglGetProcAddress(procname); - if (addr) found = true; - } - - if (found) { - addr = gExtensionForwarders[slot]; - extentionMap[name] = addr; - sGLExtentionSlot++; - } - } - - pthread_mutex_unlock(&sExtensionMapMutex); - return addr; -} - -class FrameCompletionThread { -public: - - static void queueSync(EGLSyncKHR sync) { - static FrameCompletionThread thread; - - char name[64]; - - std::lock_guard lock(thread.mMutex); - snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued); - ATRACE_NAME(name); - - thread.mQueue.push_back(sync); - thread.mCondition.notify_one(); - thread.mFramesQueued++; - ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size())); - } - -private: - - FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) { - std::thread thread(&FrameCompletionThread::loop, this); - thread.detach(); - } - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-noreturn" - void loop() { - while (true) { - threadLoop(); - } - } -#pragma clang diagnostic pop - - void threadLoop() { - EGLSyncKHR sync; - uint32_t frameNum; - { - std::unique_lock lock(mMutex); - while (mQueue.empty()) { - mCondition.wait(lock); - } - sync = mQueue[0]; - frameNum = mFramesCompleted; - } - EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); - { - char name[64]; - snprintf(name, sizeof(name), "waiting for frame %u", (unsigned int)frameNum); - ATRACE_NAME(name); - - EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR); - if (result == EGL_FALSE) { - ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError()); - } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ALOGE("FrameCompletion: timeout waiting for fence"); - } - eglDestroySyncKHR(dpy, sync); - } - { - std::lock_guard lock(mMutex); - mQueue.pop_front(); - mFramesCompleted++; - ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size())); - } - } - - uint32_t mFramesQueued; - uint32_t mFramesCompleted; - std::deque mQueue; - std::condition_variable mCondition; - std::mutex mMutex; -}; - -EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw, - EGLint *rects, EGLint n_rects) -{ - ATRACE_CALL(); - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), draw); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t* const s = get_surface(draw); - - if (CC_UNLIKELY(dp->traceGpuCompletion)) { - EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr); - if (sync != EGL_NO_SYNC_KHR) { - FrameCompletionThread::queueSync(sync); - } - } - - if (CC_UNLIKELY(dp->finishOnSwap)) { - uint32_t pixel; - egl_context_t * const c = get_context( egl_tls_t::getContext() ); - if (c) { - // glReadPixels() ensures that the frame is complete - s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1, - GL_RGBA,GL_UNSIGNED_BYTE,&pixel); - } - } - - if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { - if (!sendSurfaceMetadata(s)) { - native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL); - return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE); - } - } - - if (n_rects == 0) { - return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); - } - - std::vector androidRects((size_t)n_rects); - for (int r = 0; r < n_rects; ++r) { - int offset = r * 4; - int x = rects[offset]; - int y = rects[offset + 1]; - int width = rects[offset + 2]; - int height = rects[offset + 3]; - android_native_rect_t androidRect; - androidRect.left = x; - androidRect.top = y + height; - androidRect.right = x + width; - androidRect.bottom = y; - androidRects.push_back(androidRect); - } - if (s->cnx->angleBackend != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) { - native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), - androidRects.size()); - } - - if (s->cnx->egl.eglSwapBuffersWithDamageKHR) { - return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface, - rects, n_rects); - } else { - return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); - } -} - -EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) -{ - return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0); -} - -EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, - NativePixmapType target) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t const * const s = get_surface(surface); - return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); -} - -const char* eglQueryString(EGLDisplay dpy, EGLint name) -{ - clearError(); - - // Generate an error quietly when client extensions (as defined by - // EGL_EXT_client_extensions) are queried. We do not want to rely on - // validate_display to generate the error as validate_display would log - // the error, which can be misleading. - // - // If we want to support EGL_EXT_client_extensions later, we can return - // the client extension string here instead. - if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS) - return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return (const char *) nullptr; - - switch (name) { - case EGL_VENDOR: - return dp->getVendorString(); - case EGL_VERSION: - return dp->getVersionString(); - case EGL_EXTENSIONS: - return dp->getExtensionString(); - case EGL_CLIENT_APIS: - return dp->getClientApiString(); - default: - break; - } - return setError(EGL_BAD_PARAMETER, (const char *)nullptr); -} - -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return (const char *) nullptr; - - switch (name) { - case EGL_VENDOR: - return dp->disp.queryString.vendor; - case EGL_VERSION: - return dp->disp.queryString.version; - case EGL_EXTENSIONS: - return dp->disp.queryString.extensions; - case EGL_CLIENT_APIS: - return dp->disp.queryString.clientApi; - default: - break; - } - return setError(EGL_BAD_PARAMETER, (const char *)nullptr); -} - -// ---------------------------------------------------------------------------- -// EGL 1.1 -// ---------------------------------------------------------------------------- - -EGLBoolean eglSurfaceAttrib( - EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t * const s = get_surface(surface); - - if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) { - if (!s->getNativeWindow()) { - setError(EGL_BAD_SURFACE, EGL_FALSE); - } - int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0); - return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - if (attribute == EGL_TIMESTAMPS_ANDROID) { - if (!s->getNativeWindow()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0); - return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - if (s->setSmpte2086Attribute(attribute, value)) { - return EGL_TRUE; - } else if (s->setCta8613Attribute(attribute, value)) { - return EGL_TRUE; - } else if (s->cnx->egl.eglSurfaceAttrib) { - return s->cnx->egl.eglSurfaceAttrib( - dp->disp.dpy, s->surface, attribute, value); - } - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); -} - -EGLBoolean eglBindTexImage( - EGLDisplay dpy, EGLSurface surface, EGLint buffer) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t const * const s = get_surface(surface); - if (s->cnx->egl.eglBindTexImage) { - return s->cnx->egl.eglBindTexImage( - dp->disp.dpy, s->surface, buffer); - } - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); -} - -EGLBoolean eglReleaseTexImage( - EGLDisplay dpy, EGLSurface surface, EGLint buffer) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t const * const s = get_surface(surface); - if (s->cnx->egl.eglReleaseTexImage) { - return s->cnx->egl.eglReleaseTexImage( - dp->disp.dpy, s->surface, buffer); - } - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); -} - -EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean res = EGL_TRUE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglSwapInterval) { - res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval); - } - - return res; -} - - -// ---------------------------------------------------------------------------- -// EGL 1.2 -// ---------------------------------------------------------------------------- - -EGLBoolean eglWaitClient(void) -{ - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, (EGLBoolean)EGL_FALSE); - - EGLBoolean res; - if (cnx->egl.eglWaitClient) { - res = cnx->egl.eglWaitClient(); - } else { - res = cnx->egl.eglWaitGL(); - } - return res; -} - -EGLBoolean eglBindAPI(EGLenum api) -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - // bind this API on all EGLs - EGLBoolean res = EGL_TRUE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglBindAPI) { - res = cnx->egl.eglBindAPI(api); - } - return res; -} - -EGLenum eglQueryAPI(void) -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglQueryAPI) { - return cnx->egl.eglQueryAPI(); - } - - // or, it can only be OpenGL ES - return EGL_OPENGL_ES_API; -} - -EGLBoolean eglReleaseThread(void) -{ - clearError(); - - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglReleaseThread) { - cnx->egl.eglReleaseThread(); - } - - // If there is context bound to the thread, release it - egl_display_t::loseCurrent(get_context(getContext())); - - egl_tls_t::clearTLS(); - return EGL_TRUE; -} - -EGLSurface eglCreatePbufferFromClientBuffer( - EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, - EGLConfig config, const EGLint *attrib_list) -{ - clearError(); - - egl_connection_t* cnx = nullptr; - const egl_display_ptr dp = validate_display_connection(dpy, cnx); - if (!dp) return EGL_FALSE; - if (cnx->egl.eglCreatePbufferFromClientBuffer) { - return cnx->egl.eglCreatePbufferFromClientBuffer( - dp->disp.dpy, buftype, buffer, config, attrib_list); - } - return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); -} - -// ---------------------------------------------------------------------------- -// EGL_EGLEXT_VERSION 3 -// ---------------------------------------------------------------------------- - -EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, - const EGLint *attrib_list) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t const * const s = get_surface(surface); - if (s->cnx->egl.eglLockSurfaceKHR) { - return s->cnx->egl.eglLockSurfaceKHR( - dp->disp.dpy, s->surface, attrib_list); - } - return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); -} - -EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - - egl_surface_t const * const s = get_surface(surface); - if (s->cnx->egl.eglUnlockSurfaceKHR) { - return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface); - } - return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); -} - -EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, - EGLClientBuffer buffer, const EGLint *attrib_list) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_NO_IMAGE_KHR; - - ContextRef _c(dp.get(), ctx); - egl_context_t * const c = _c.get(); - - EGLImageKHR result = EGL_NO_IMAGE_KHR; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglCreateImageKHR) { - result = cnx->egl.eglCreateImageKHR( - dp->disp.dpy, - c ? c->context : EGL_NO_CONTEXT, - target, buffer, attrib_list); - } - return result; -} - -EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglDestroyImageKHR) { - result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img); - } - return result; -} - -// ---------------------------------------------------------------------------- -// EGL_EGLEXT_VERSION 5 -// ---------------------------------------------------------------------------- - - -EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_NO_SYNC_KHR; - - EGLSyncKHR result = EGL_NO_SYNC_KHR; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglCreateSyncKHR) { - result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); - } - return result; -} - -EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglDestroySyncKHR) { - result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync); - } - return result; -} - -EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglSignalSyncKHR) { - result = cnx->egl.eglSignalSyncKHR( - dp->disp.dpy, sync, mode); - } - return result; -} - -EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, - EGLint flags, EGLTimeKHR timeout) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLint result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) { - result = cnx->egl.eglClientWaitSyncKHR( - dp->disp.dpy, sync, flags, timeout); - } - return result; -} - -EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, - EGLint attribute, EGLint *value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) { - result = cnx->egl.eglGetSyncAttribKHR( - dp->disp.dpy, sync, attribute, value); - } - return result; -} - -EGLStreamKHR eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_NO_STREAM_KHR; - - EGLStreamKHR result = EGL_NO_STREAM_KHR; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglCreateStreamKHR) { - result = cnx->egl.eglCreateStreamKHR( - dp->disp.dpy, attrib_list); - } - return result; -} - -EGLBoolean eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglDestroyStreamKHR) { - result = cnx->egl.eglDestroyStreamKHR( - dp->disp.dpy, stream); - } - return result; -} - -EGLBoolean eglStreamAttribKHR(EGLDisplay dpy, EGLStreamKHR stream, - EGLenum attribute, EGLint value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglStreamAttribKHR) { - result = cnx->egl.eglStreamAttribKHR( - dp->disp.dpy, stream, attribute, value); - } - return result; -} - -EGLBoolean eglQueryStreamKHR(EGLDisplay dpy, EGLStreamKHR stream, - EGLenum attribute, EGLint *value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglQueryStreamKHR) { - result = cnx->egl.eglQueryStreamKHR( - dp->disp.dpy, stream, attribute, value); - } - return result; -} - -EGLBoolean eglQueryStreamu64KHR(EGLDisplay dpy, EGLStreamKHR stream, - EGLenum attribute, EGLuint64KHR *value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglQueryStreamu64KHR) { - result = cnx->egl.eglQueryStreamu64KHR( - dp->disp.dpy, stream, attribute, value); - } - return result; -} - -EGLBoolean eglQueryStreamTimeKHR(EGLDisplay dpy, EGLStreamKHR stream, - EGLenum attribute, EGLTimeKHR *value) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglQueryStreamTimeKHR) { - result = cnx->egl.eglQueryStreamTimeKHR( - dp->disp.dpy, stream, attribute, value); - } - return result; -} - -EGLSurface eglCreateStreamProducerSurfaceKHR(EGLDisplay dpy, EGLConfig config, - EGLStreamKHR stream, const EGLint *attrib_list) -{ - clearError(); - - egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_NO_SURFACE; - - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglCreateStreamProducerSurfaceKHR) { - EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR( - dp->disp.dpy, config, stream, attrib_list); - if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface, - EGL_GL_COLORSPACE_LINEAR_KHR, cnx); - return s; - } - } - return EGL_NO_SURFACE; -} - -EGLBoolean eglStreamConsumerGLTextureExternalKHR(EGLDisplay dpy, - EGLStreamKHR stream) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglStreamConsumerGLTextureExternalKHR) { - result = cnx->egl.eglStreamConsumerGLTextureExternalKHR( - dp->disp.dpy, stream); - } - return result; -} - -EGLBoolean eglStreamConsumerAcquireKHR(EGLDisplay dpy, - EGLStreamKHR stream) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglStreamConsumerAcquireKHR) { - result = cnx->egl.eglStreamConsumerAcquireKHR( - dp->disp.dpy, stream); - } - return result; -} - -EGLBoolean eglStreamConsumerReleaseKHR(EGLDisplay dpy, - EGLStreamKHR stream) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - - EGLBoolean result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglStreamConsumerReleaseKHR) { - result = cnx->egl.eglStreamConsumerReleaseKHR( - dp->disp.dpy, stream); - } - return result; -} - -EGLNativeFileDescriptorKHR eglGetStreamFileDescriptorKHR( - EGLDisplay dpy, EGLStreamKHR stream) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_NO_FILE_DESCRIPTOR_KHR; - - EGLNativeFileDescriptorKHR result = EGL_NO_FILE_DESCRIPTOR_KHR; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglGetStreamFileDescriptorKHR) { - result = cnx->egl.eglGetStreamFileDescriptorKHR( - dp->disp.dpy, stream); - } - return result; -} - -EGLStreamKHR eglCreateStreamFromFileDescriptorKHR( - EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_NO_STREAM_KHR; - - EGLStreamKHR result = EGL_NO_STREAM_KHR; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglCreateStreamFromFileDescriptorKHR) { - result = cnx->egl.eglCreateStreamFromFileDescriptorKHR( - dp->disp.dpy, file_descriptor); - } - return result; -} - -// ---------------------------------------------------------------------------- -// EGL_EGLEXT_VERSION 15 -// ---------------------------------------------------------------------------- - -EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags) { - clearError(); - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_FALSE; - EGLint result = EGL_FALSE; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglWaitSyncKHR) { - result = cnx->egl.eglWaitSyncKHR(dp->disp.dpy, sync, flags); - } - return result; -} - -// ---------------------------------------------------------------------------- -// ANDROID extensions -// ---------------------------------------------------------------------------- - -EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID; - - EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID; - egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) { - result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync); - } - return result; -} - -EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface, - EGLnsecsANDROID time) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - return EGL_FALSE; - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - setError(EGL_BAD_SURFACE, EGL_FALSE); - return EGL_FALSE; - } - - egl_surface_t const * const s = get_surface(surface); - native_window_set_buffers_timestamp(s->getNativeWindow(), time); - - return EGL_TRUE; -} - -EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) { - clearError(); - // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus - // this function cannot be implemented when this libEGL is built for - // vendors. -#ifndef __ANDROID_VNDK__ - if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); - return const_cast(AHardwareBuffer_to_ANativeWindowBuffer(buffer)); -#else - return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr); -#endif -} - -// ---------------------------------------------------------------------------- -// NVIDIA extensions -// ---------------------------------------------------------------------------- -EGLuint64NV eglGetSystemTimeFrequencyNV() -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - - EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl; - - if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { - return cnx->egl.eglGetSystemTimeFrequencyNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -EGLuint64NV eglGetSystemTimeNV() -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, (EGLuint64NV)EGL_FALSE); - } - - EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl; - - if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { - return cnx->egl.eglGetSystemTimeNV(); - } - - return setErrorQuiet(EGL_BAD_DISPLAY, (EGLuint64NV)0); -} - -// ---------------------------------------------------------------------------- -// Partial update extension -// ---------------------------------------------------------------------------- -EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface, - EGLint *rects, EGLint n_rects) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - setError(EGL_BAD_DISPLAY, EGL_FALSE); - return EGL_FALSE; - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - setError(EGL_BAD_SURFACE, EGL_FALSE); - return EGL_FALSE; - } - - egl_surface_t const * const s = get_surface(surface); - if (s->cnx->egl.eglSetDamageRegionKHR) { - return s->cnx->egl.eglSetDamageRegionKHR(dp->disp.dpy, s->surface, - rects, n_rects); - } - - return EGL_FALSE; -} - -EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, - EGLuint64KHR *frameId) { - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - egl_surface_t const * const s = get_surface(surface); - - if (!s->getNativeWindow()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - uint64_t nextFrameId = 0; - int ret = native_window_get_next_frame_id(s->getNativeWindow(), &nextFrameId); - - if (ret != 0) { - // This should not happen. Return an error that is not in the spec - // so it's obvious something is very wrong. - ALOGE("eglGetNextFrameId: Unexpected error."); - return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); - } - - *frameId = nextFrameId; - return EGL_TRUE; -} - -EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, - EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - egl_surface_t const * const s = get_surface(surface); - - if (!s->getNativeWindow()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - nsecs_t* compositeDeadline = nullptr; - nsecs_t* compositeInterval = nullptr; - nsecs_t* compositeToPresentLatency = nullptr; - - for (int i = 0; i < numTimestamps; i++) { - switch (names[i]) { - case EGL_COMPOSITE_DEADLINE_ANDROID: - compositeDeadline = &values[i]; - break; - case EGL_COMPOSITE_INTERVAL_ANDROID: - compositeInterval = &values[i]; - break; - case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID: - compositeToPresentLatency = &values[i]; - break; - default: - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - } - - int ret = native_window_get_compositor_timing(s->getNativeWindow(), - compositeDeadline, compositeInterval, compositeToPresentLatency); - - switch (ret) { - case 0: - return EGL_TRUE; - case -ENOSYS: - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - default: - // This should not happen. Return an error that is not in the spec - // so it's obvious something is very wrong. - ALOGE("eglGetCompositorTiming: Unexpected error."); - return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); - } -} - -EGLBoolean eglGetCompositorTimingSupportedANDROID( - EGLDisplay dpy, EGLSurface surface, EGLint name) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - egl_surface_t const * const s = get_surface(surface); - - ANativeWindow* window = s->getNativeWindow(); - if (!window) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - switch (name) { - case EGL_COMPOSITE_DEADLINE_ANDROID: - case EGL_COMPOSITE_INTERVAL_ANDROID: - case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID: - return EGL_TRUE; - default: - return EGL_FALSE; - } -} - -EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, - EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, - EGLnsecsANDROID *values) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - egl_surface_t const * const s = get_surface(surface); - - if (!s->getNativeWindow()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - nsecs_t* requestedPresentTime = nullptr; - nsecs_t* acquireTime = nullptr; - nsecs_t* latchTime = nullptr; - nsecs_t* firstRefreshStartTime = nullptr; - nsecs_t* gpuCompositionDoneTime = nullptr; - nsecs_t* lastRefreshStartTime = nullptr; - nsecs_t* displayPresentTime = nullptr; - nsecs_t* dequeueReadyTime = nullptr; - nsecs_t* releaseTime = nullptr; - - for (int i = 0; i < numTimestamps; i++) { - switch (timestamps[i]) { - case EGL_REQUESTED_PRESENT_TIME_ANDROID: - requestedPresentTime = &values[i]; - break; - case EGL_RENDERING_COMPLETE_TIME_ANDROID: - acquireTime = &values[i]; - break; - case EGL_COMPOSITION_LATCH_TIME_ANDROID: - latchTime = &values[i]; - break; - case EGL_FIRST_COMPOSITION_START_TIME_ANDROID: - firstRefreshStartTime = &values[i]; - break; - case EGL_LAST_COMPOSITION_START_TIME_ANDROID: - lastRefreshStartTime = &values[i]; - break; - case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID: - gpuCompositionDoneTime = &values[i]; - break; - case EGL_DISPLAY_PRESENT_TIME_ANDROID: - displayPresentTime = &values[i]; - break; - case EGL_DEQUEUE_READY_TIME_ANDROID: - dequeueReadyTime = &values[i]; - break; - case EGL_READS_DONE_TIME_ANDROID: - releaseTime = &values[i]; - break; - default: - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - } - } - - int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId, - requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime, - lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime, - dequeueReadyTime, releaseTime); - - switch (ret) { - case 0: - return EGL_TRUE; - case -ENOENT: - return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE); - case -ENOSYS: - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - case -EINVAL: - return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE); - default: - // This should not happen. Return an error that is not in the spec - // so it's obvious something is very wrong. - ALOGE("eglGetFrameTimestamps: Unexpected error."); - return setError(EGL_NOT_INITIALIZED, (EGLBoolean)EGL_FALSE); - } -} - -EGLBoolean eglGetFrameTimestampSupportedANDROID( - EGLDisplay dpy, EGLSurface surface, EGLint timestamp) -{ - clearError(); - - const egl_display_ptr dp = validate_display(dpy); - if (!dp) { - return setError(EGL_BAD_DISPLAY, (EGLBoolean)EGL_FALSE); - } - - SurfaceRef _s(dp.get(), surface); - if (!_s.get()) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - egl_surface_t const * const s = get_surface(surface); - - ANativeWindow* window = s->getNativeWindow(); - if (!window) { - return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } - - switch (timestamp) { - case EGL_COMPOSITE_DEADLINE_ANDROID: - case EGL_COMPOSITE_INTERVAL_ANDROID: - case EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID: - case EGL_REQUESTED_PRESENT_TIME_ANDROID: - case EGL_RENDERING_COMPLETE_TIME_ANDROID: - case EGL_COMPOSITION_LATCH_TIME_ANDROID: - case EGL_FIRST_COMPOSITION_START_TIME_ANDROID: - case EGL_LAST_COMPOSITION_START_TIME_ANDROID: - case EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID: - case EGL_DEQUEUE_READY_TIME_ANDROID: - case EGL_READS_DONE_TIME_ANDROID: - return EGL_TRUE; - case EGL_DISPLAY_PRESENT_TIME_ANDROID: { - int value = 0; - window->query(window, - NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &value); - return value == 0 ? EGL_FALSE : EGL_TRUE; - } - default: - return EGL_FALSE; - } -} -- cgit v1.2.3-59-g8ed1b From f1d2d87687c653a41dbd4c5769deb8043569ee9d Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 15 Nov 2018 00:00:50 +0000 Subject: Revert "Delete renderengine::Surface" This reverts commit c956fa24bb8c1d433fd2ff62f69a03be8ecd59f3. Reason for revert: breaks screenrecord (b/119534075) Change-Id: Id50e0d23c44895f547e23fbd31f9102db0c75316 (cherry picked from commit f1d19c710e1e410a2307503c504bdf150f013ccd) --- libs/renderengine/Android.bp | 1 + libs/renderengine/gl/GLES20RenderEngine.cpp | 38 +++++++- libs/renderengine/gl/GLES20RenderEngine.h | 6 ++ libs/renderengine/gl/GLSurface.cpp | 105 +++++++++++++++++++++ libs/renderengine/gl/GLSurface.h | 76 +++++++++++++++ .../include/renderengine/RenderEngine.h | 4 + libs/renderengine/include/renderengine/Surface.h | 46 +++++++++ .../mock/RenderEngine/MockRenderEngine.cpp | 3 + .../unittests/mock/RenderEngine/MockRenderEngine.h | 21 +++++ 9 files changed, 298 insertions(+), 2 deletions(-) create mode 100644 libs/renderengine/gl/GLSurface.cpp create mode 100644 libs/renderengine/gl/GLSurface.h create mode 100644 libs/renderengine/include/renderengine/Surface.h diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index beaf9ee70d..7efc8bd64d 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -50,6 +50,7 @@ filegroup { "gl/GLExtensions.cpp", "gl/GLFramebuffer.cpp", "gl/GLImage.cpp", + "gl/GLSurface.cpp", "gl/Program.cpp", "gl/ProgramCache.cpp", ], diff --git a/libs/renderengine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp index d35762d447..e244a83c09 100644 --- a/libs/renderengine/gl/GLES20RenderEngine.cpp +++ b/libs/renderengine/gl/GLES20RenderEngine.cpp @@ -41,6 +41,7 @@ #include "GLExtensions.h" #include "GLFramebuffer.h" #include "GLImage.h" +#include "GLSurface.h" #include "Program.h" #include "ProgramCache.h" @@ -422,6 +423,10 @@ std::unique_ptr GLES20RenderEngine::createFramebuffer() { return std::make_unique(*this); } +std::unique_ptr GLES20RenderEngine::createSurface() { + return std::make_unique(*this); +} + std::unique_ptr GLES20RenderEngine::createImage() { return std::make_unique(*this); } @@ -434,6 +439,31 @@ bool GLES20RenderEngine::isCurrent() const { return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext(); } +bool GLES20RenderEngine::setCurrentSurface(const Surface& surface) { + // Surface is an abstract interface. GLES20RenderEngine only ever + // creates GLSurface's, so it is safe to just cast to the actual + // type. + bool success = true; + const GLSurface& glSurface = static_cast(surface); + EGLSurface eglSurface = glSurface.getEGLSurface(); + if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) { + success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE; + if (success && glSurface.getAsync()) { + eglSwapInterval(mEGLDisplay, 0); + } + if (success) { + mSurfaceHeight = glSurface.getHeight(); + } + } + + return success; +} + +void GLES20RenderEngine::resetCurrentSurface() { + eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + mSurfaceHeight = 0; +} + base::unique_fd GLES20RenderEngine::flush() { if (!GLExtensions::getInstance().hasNativeFenceSync()) { return base::unique_fd(); @@ -547,7 +577,7 @@ void GLES20RenderEngine::fillRegionWithColor(const Region& region, float red, fl void GLES20RenderEngine::setScissor(const Rect& region) { // Invert y-coordinate to map to GL-space. - int32_t canvasHeight = mFboHeight; + int32_t canvasHeight = mRenderToFbo ? mFboHeight : mSurfaceHeight; int32_t glBottom = canvasHeight - region.bottom; glScissor(region.left, glBottom, region.getWidth(), region.getHeight()); @@ -590,6 +620,7 @@ status_t GLES20RenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { glBindFramebuffer(GL_FRAMEBUFFER, framebufferName); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); + mRenderToFbo = true; mFboHeight = glFramebuffer->getBufferHeight(); uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -601,6 +632,7 @@ status_t GLES20RenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { } void GLES20RenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) { + mRenderToFbo = false; mFboHeight = 0; // back to main framebuffer @@ -629,7 +661,9 @@ void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect s int32_t r = sourceCrop.right; int32_t b = sourceCrop.bottom; int32_t t = sourceCrop.top; - std::swap(t, b); + if (mRenderToFbo) { + std::swap(t, b); + } mat4 m = mat4::ortho(l, r, b, t, 0, 1); // Apply custom rotation to the projection. diff --git a/libs/renderengine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h index 6c50938863..aebb319a99 100644 --- a/libs/renderengine/gl/GLES20RenderEngine.h +++ b/libs/renderengine/gl/GLES20RenderEngine.h @@ -40,6 +40,7 @@ class Texture; namespace gl { class GLImage; +class GLSurface; class GLES20RenderEngine : public impl::RenderEngine { public: @@ -51,10 +52,13 @@ public: ~GLES20RenderEngine() override; std::unique_ptr createFramebuffer() override; + std::unique_ptr createSurface() override; std::unique_ptr createImage() override; void primeCache() const override; bool isCurrent() const override; + bool setCurrentSurface(const Surface& surface) override; + void resetCurrentSurface() override; base::unique_fd flush() override; bool finish() override; bool waitFence(base::unique_fd fenceFd) override; @@ -143,6 +147,8 @@ private: mat4 mBt2020ToSrgb; mat4 mBt2020ToDisplayP3; + bool mRenderToFbo = false; + int32_t mSurfaceHeight = 0; int32_t mFboHeight = 0; // Current dataspace of layer being rendered diff --git a/libs/renderengine/gl/GLSurface.cpp b/libs/renderengine/gl/GLSurface.cpp new file mode 100644 index 0000000000..2d694e9124 --- /dev/null +++ b/libs/renderengine/gl/GLSurface.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2018 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. + */ + +#include "GLSurface.h" + +#include +#include +#include +#include "GLES20RenderEngine.h" + +namespace android { +namespace renderengine { +namespace gl { + +GLSurface::GLSurface(const GLES20RenderEngine& engine) + : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) { + // RE does not assume any config when EGL_KHR_no_config_context is supported + if (mEGLConfig == EGL_NO_CONFIG_KHR) { + mEGLConfig = + GLES20RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false); + } +} + +GLSurface::~GLSurface() { + setNativeWindow(nullptr); +} + +void GLSurface::setNativeWindow(ANativeWindow* window) { + if (mEGLSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEGLDisplay, mEGLSurface); + mEGLSurface = EGL_NO_SURFACE; + mSurfaceWidth = 0; + mSurfaceHeight = 0; + } + + mWindow = window; + if (mWindow) { + mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mWindow, nullptr); + mSurfaceWidth = ANativeWindow_getWidth(window); + mSurfaceHeight = ANativeWindow_getHeight(window); + } +} + +void GLSurface::swapBuffers() const { + if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) { + EGLint error = eglGetError(); + + const char format[] = "eglSwapBuffers(%p, %p) failed with 0x%08x"; + if (mCritical || error == EGL_CONTEXT_LOST) { + LOG_ALWAYS_FATAL(format, mEGLDisplay, mEGLSurface, error); + } else { + ALOGE(format, mEGLDisplay, mEGLSurface, error); + } + } +} + +EGLint GLSurface::queryConfig(EGLint attrib) const { + EGLint value; + if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) { + value = 0; + } + + return value; +} + +int32_t GLSurface::queryRedSize() const { + return queryConfig(EGL_RED_SIZE); +} + +int32_t GLSurface::queryGreenSize() const { + return queryConfig(EGL_GREEN_SIZE); +} + +int32_t GLSurface::queryBlueSize() const { + return queryConfig(EGL_BLUE_SIZE); +} + +int32_t GLSurface::queryAlphaSize() const { + return queryConfig(EGL_ALPHA_SIZE); +} + +int32_t GLSurface::getWidth() const { + return mSurfaceWidth; +} + +int32_t GLSurface::getHeight() const { + return mSurfaceHeight; +} + +} // namespace gl +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/gl/GLSurface.h b/libs/renderengine/gl/GLSurface.h new file mode 100644 index 0000000000..092d371ee9 --- /dev/null +++ b/libs/renderengine/gl/GLSurface.h @@ -0,0 +1,76 @@ +/* + * Copyright 2018 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. + */ + +#pragma once + +#include + +#include +#include +#include + +struct ANativeWindow; + +namespace android { +namespace renderengine { +namespace gl { + +class GLES20RenderEngine; + +class GLSurface final : public renderengine::Surface { +public: + GLSurface(const GLES20RenderEngine& engine); + ~GLSurface() override; + + // renderengine::Surface implementation + void setCritical(bool enable) override { mCritical = enable; } + void setAsync(bool enable) override { mAsync = enable; } + + void setNativeWindow(ANativeWindow* window) override; + void swapBuffers() const override; + + int32_t queryRedSize() const override; + int32_t queryGreenSize() const override; + int32_t queryBlueSize() const override; + int32_t queryAlphaSize() const override; + + bool getAsync() const { return mAsync; } + EGLSurface getEGLSurface() const { return mEGLSurface; } + + int32_t getWidth() const override; + int32_t getHeight() const override; + +private: + EGLint queryConfig(EGLint attrib) const; + + EGLDisplay mEGLDisplay; + EGLConfig mEGLConfig; + + bool mCritical = false; + bool mAsync = false; + + int32_t mSurfaceWidth = 0; + int32_t mSurfaceHeight = 0; + + ANativeWindow* mWindow = nullptr; + EGLSurface mEGLSurface = EGL_NO_SURFACE; + + DISALLOW_COPY_AND_ASSIGN(GLSurface); +}; + +} // namespace gl +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 22891c42c4..becb3c3a10 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -48,6 +48,7 @@ namespace renderengine { class BindNativeBufferAsFramebuffer; class Image; class Mesh; +class Surface; class Texture; namespace impl { @@ -71,6 +72,7 @@ public: // used to support legacy behavior. virtual std::unique_ptr createFramebuffer() = 0; + virtual std::unique_ptr createSurface() = 0; virtual std::unique_ptr createImage() = 0; virtual void primeCache() const = 0; @@ -82,6 +84,8 @@ public: virtual bool useWaitSync() const = 0; virtual bool isCurrent() const = 0; + virtual bool setCurrentSurface(const Surface& surface) = 0; + virtual void resetCurrentSurface() = 0; // helpers // flush submits RenderEngine command stream for execution and returns a diff --git a/libs/renderengine/include/renderengine/Surface.h b/libs/renderengine/include/renderengine/Surface.h new file mode 100644 index 0000000000..ba7331daab --- /dev/null +++ b/libs/renderengine/include/renderengine/Surface.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 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. + */ + +#pragma once + +#include + +struct ANativeWindow; + +namespace android { +namespace renderengine { + +class Surface { +public: + virtual ~Surface() = default; + + virtual void setCritical(bool enable) = 0; + virtual void setAsync(bool enable) = 0; + + virtual void setNativeWindow(ANativeWindow* window) = 0; + virtual void swapBuffers() const = 0; + + virtual int32_t queryRedSize() const = 0; + virtual int32_t queryGreenSize() const = 0; + virtual int32_t queryBlueSize() const = 0; + virtual int32_t queryAlphaSize() const = 0; + + virtual int32_t getWidth() const = 0; + virtual int32_t getHeight() const = 0; +}; + +} // namespace renderengine +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp index fbfbc3fc99..af54df6d2b 100644 --- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp +++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp @@ -26,6 +26,9 @@ namespace mock { RenderEngine::RenderEngine() = default; RenderEngine::~RenderEngine() = default; +Surface::Surface() = default; +Surface::~Surface() = default; + Image::Image() = default; Image::~Image() = default; diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h index 90c3c20b68..afca63ad39 100644 --- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h +++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -36,12 +37,15 @@ public: ~RenderEngine() override; MOCK_METHOD0(createFramebuffer, std::unique_ptr()); + MOCK_METHOD0(createSurface, std::unique_ptr()); MOCK_METHOD0(createImage, std::unique_ptr()); MOCK_CONST_METHOD0(primeCache, void()); MOCK_METHOD1(dump, void(String8&)); MOCK_CONST_METHOD0(useNativeFenceSync, bool()); MOCK_CONST_METHOD0(useWaitSync, bool()); MOCK_CONST_METHOD0(isCurrent, bool()); + MOCK_METHOD1(setCurrentSurface, bool(const renderengine::Surface&)); + MOCK_METHOD0(resetCurrentSurface, void()); MOCK_METHOD0(flush, base::unique_fd()); MOCK_METHOD0(finish, bool()); MOCK_METHOD1(waitFence, bool(base::unique_fd*)); @@ -78,6 +82,23 @@ public: ANativeWindowBuffer* const, base::unique_fd*)); }; +class Surface : public renderengine::Surface { +public: + Surface(); + ~Surface() override; + + MOCK_METHOD1(setCritical, void(bool)); + MOCK_METHOD1(setAsync, void(bool)); + MOCK_METHOD1(setNativeWindow, void(ANativeWindow*)); + MOCK_CONST_METHOD0(swapBuffers, void()); + MOCK_CONST_METHOD0(queryRedSize, int32_t()); + MOCK_CONST_METHOD0(queryGreenSize, int32_t()); + MOCK_CONST_METHOD0(queryBlueSize, int32_t()); + MOCK_CONST_METHOD0(queryAlphaSize, int32_t()); + MOCK_CONST_METHOD0(getWidth, int32_t()); + MOCK_CONST_METHOD0(getHeight, int32_t()); +}; + class Image : public renderengine::Image { public: Image(); -- cgit v1.2.3-59-g8ed1b From 18e16fae5dad9492fad167b82ec71a2faa5483b7 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 14 Nov 2018 22:34:02 +0000 Subject: Revert "Remove gl surfaces from DisplayDevice." This reverts commit ce0ad96d3c23b6b7bc4d6a540141ea1111b4430e. Reason for revert: breaks screenrecord (b/119534075) Change-Id: I45af7b49a490601fcc68ca55c79f590bb0db1b01 (cherry picked from commit 0587464f761d06512181f44b47bd950033a907ae) --- services/surfaceflinger/DisplayDevice.cpp | 27 ++++++++++++++++------ services/surfaceflinger/DisplayDevice.h | 8 +++++-- services/surfaceflinger/SurfaceFlinger.cpp | 8 +++++++ .../tests/unittests/CompositionTest.cpp | 7 +++--- .../tests/unittests/DisplayTransactionTest.cpp | 17 ++++++++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 5 ++++ 6 files changed, 59 insertions(+), 13 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index d16febfaa2..d5b24ae56c 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -225,6 +225,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) mNativeWindow(args.nativeWindow), mGraphicBuffer(nullptr), mDisplaySurface(args.displaySurface), + mSurface{std::move(args.renderSurface)}, mDisplayInstallOrientation(args.displayInstallOrientation), mPageFlipCount(0), mIsVirtual(args.isVirtual), @@ -246,6 +247,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) ALOGE_IF(!mNativeWindow, "No native window was set for display"); ALOGE_IF(!mDisplaySurface, "No display surface was set for display"); + ALOGE_IF(!mSurface, "No render surface was set for display"); std::vector types = args.hdrCapabilities.getSupportedHdrTypes(); for (Hdr hdrType : types) { @@ -437,6 +439,12 @@ void DisplayDevice::onPresentDisplayCompleted() { mDisplaySurface->onFrameCommitted(); } +bool DisplayDevice::makeCurrent() const { + bool success = mFlinger->getRenderEngine().setCurrentSurface(*mSurface); + setViewportAndProjection(); + return success; +} + void DisplayDevice::setViewportAndProjection() const { size_t w = mDisplayWidth; size_t h = mDisplayHeight; @@ -599,8 +607,12 @@ status_t DisplayDevice::orientationToTransfrom( void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) { dirtyRegion.set(getBounds()); + mSurface->setNativeWindow(nullptr); + mDisplaySurface->resizeBuffers(newWidth, newHeight); + ANativeWindow* const window = mNativeWindow.get(); + mSurface->setNativeWindow(window); mDisplayWidth = newWidth; mDisplayHeight = newHeight; } @@ -716,11 +728,12 @@ void DisplayDevice::dump(String8& result) const { ANativeWindow* const window = mNativeWindow.get(); result.appendFormat("+ %s\n", getDebugName().c_str()); result.appendFormat(" layerStack=%u, (%4dx%4d), ANativeWindow=%p " - "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, " - "powerMode=%d, activeConfig=%d, numLayers=%zu\n", + "(%d:%d:%d:%d), orient=%2d (type=%08x), " + "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n", mLayerStack, mDisplayWidth, mDisplayHeight, window, - ANativeWindow_getFormat(window), mOrientation, tr.getType(), - getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, + mSurface->queryRedSize(), mSurface->queryGreenSize(), + mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation, + tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size()); result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d]," "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n", @@ -731,9 +744,9 @@ void DisplayDevice::dump(String8& result) const { auto const surface = static_cast(window); ui::Dataspace dataspace = surface->getBuffersDataSpace(); result.appendFormat(" wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n", - mHasWideColorGamut, mHasHdr10, decodeColorMode(mActiveColorMode).c_str(), - dataspaceDetails(static_cast(dataspace)).c_str(), - dataspace); + mHasWideColorGamut, mHasHdr10, + decodeColorMode(mActiveColorMode).c_str(), + dataspaceDetails(static_cast(dataspace)).c_str(), dataspace); String8 surfaceDump; mDisplaySurface->dumpAsString(surfaceDump); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index eb2c5c3f94..560a9588b5 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -24,13 +24,12 @@ #include #include -#include #include #include #include #include #include -#include +#include #include #include #include @@ -43,6 +42,8 @@ #include "DisplayHardware/DisplayIdentification.h" #include "RenderArea.h" +struct ANativeWindow; + namespace android { class DisplaySurface; @@ -162,6 +163,7 @@ public: void setDisplayName(const std::string& displayName); const std::string& getDisplayName() const { return mDisplayName; } + bool makeCurrent() const; // Acquires a new buffer for GPU composition. void readyNewBuffer(); // Marks the current buffer has finished, so that it can be presented and @@ -218,6 +220,7 @@ private: // that drawing to the buffer is now complete. base::unique_fd mBufferReady; + std::unique_ptr mSurface; int mDisplayWidth; int mDisplayHeight; const int mDisplayInstallOrientation; @@ -337,6 +340,7 @@ struct DisplayDeviceCreationArgs { bool isSecure{false}; sp nativeWindow; sp displaySurface; + std::unique_ptr renderSurface; int displayInstallOrientation{DisplayState::eOrientationDefault}; bool hasWideColorGamut{false}; HdrCapabilities hdrCapabilities; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e84e21a462..3f3c497fc7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2337,6 +2337,14 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( auto nativeWindow = nativeWindowSurface->getNativeWindow(); creationArgs.nativeWindow = nativeWindow; + /* + * Create our display's surface + */ + std::unique_ptr renderSurface = getRenderEngine().createSurface(); + renderSurface->setCritical(isInternalDisplay); + renderSurface->setAsync(state.isVirtual()); + creationArgs.renderSurface = std::move(renderSurface); + // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. We have to do this // here, in case the display is composed entirely by HWC. diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index cfaf495767..6d3e71562d 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -94,10 +94,6 @@ public: EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0)); EXPECT_CALL(*mPrimaryDispSync, getPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE)); - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0))); - EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0))); mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); setupComposer(0); @@ -144,6 +140,7 @@ public: sp mDisplay; sp mExternalDisplay; sp mDisplaySurface = new mock::DisplaySurface(); + renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface(); mock::NativeWindow* mNativeWindow = new mock::NativeWindow(); sp mBuffer = new GraphicBuffer(); @@ -249,6 +246,8 @@ struct BaseDisplayVariant { test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */, true /* isPrimary */) .setDisplaySurface(test->mDisplaySurface) + .setRenderSurface(std::unique_ptr( + test->mRenderSurface)) .setNativeWindow(test->mNativeWindow) .setSecure(Derived::IS_SECURE) .setPowerMode(Derived::INIT_POWER_MODE) diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index ac6a78b75f..4923785a28 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -135,6 +135,7 @@ public: sp mConsumer; sp mProducer; surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr; + renderengine::mock::Surface* mRenderSurface = nullptr; }; DisplayTransactionTest::DisplayTransactionTest() { @@ -341,10 +342,22 @@ struct DisplayVariant { EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow()) .WillOnce(Return(test->mNativeWindow)); + // For simplicity, we only expect to create a single render surface for + // each test. + ASSERT_TRUE(test->mRenderSurface == nullptr); + test->mRenderSurface = new renderengine::mock::Surface(); + EXPECT_CALL(*test->mRenderEngine, createSurface()) + .WillOnce(Return(ByMove( + std::unique_ptr(test->mRenderSurface)))); EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0))); EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0))); + + // Creating a DisplayDevice requires getting default dimensions from the + // native window. + EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast(ASYNC))).Times(1); + EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast(CRITICAL))).Times(1); } static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) { @@ -1931,10 +1944,12 @@ TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) { // A display is set up auto nativeWindow = new mock::NativeWindow(); auto displaySurface = new mock::DisplaySurface(); + auto renderSurface = new renderengine::mock::Surface(); sp buf = new GraphicBuffer(); auto display = Case::Display::makeFakeExistingDisplayInjector(this); display.setNativeWindow(nativeWindow); display.setDisplaySurface(displaySurface); + display.setRenderSurface(std::unique_ptr(renderSurface)); // Setup injection expections EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); @@ -1973,10 +1988,12 @@ TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) { // A display is set up auto nativeWindow = new mock::NativeWindow(); auto displaySurface = new mock::DisplaySurface(); + auto renderSurface = new renderengine::mock::Surface(); sp buf = new GraphicBuffer(); auto display = Case::Display::makeFakeExistingDisplayInjector(this); display.setNativeWindow(nativeWindow); display.setDisplaySurface(displaySurface); + display.setRenderSurface(std::unique_ptr(renderSurface)); // Setup injection expections EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 85c835e2e5..a519f1fb52 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -474,6 +474,11 @@ public: return *this; } + auto& setRenderSurface(std::unique_ptr renderSurface) { + mCreationArgs.renderSurface = std::move(renderSurface); + return *this; + } + auto& setSecure(bool secure) { mCreationArgs.isSecure = secure; return *this; -- cgit v1.2.3-59-g8ed1b From 3b72ee4785c696bcb47b37c129648b7b5d0bdbc2 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 14 Nov 2018 22:33:24 +0000 Subject: Revert "Bind to FBO when using GPU composition" This reverts commit 8147b0ead81c2d26e38fb4d93bc6d2f499ebd470. Reason for revert: Breaks screenrecord (b/119534075). Change-Id: Iea02806d896ac53c805c27ed745f325456d9a3a4 (cherry picked from commit 8d4f90aaadf9f3be77d258d2acd67b6186352811) --- libs/renderengine/gl/GLES20RenderEngine.cpp | 31 +++++--- libs/renderengine/gl/GLES20RenderEngine.h | 6 +- services/surfaceflinger/Android.bp | 1 - services/surfaceflinger/DisplayDevice.cpp | 83 ++-------------------- services/surfaceflinger/DisplayDevice.h | 20 +----- .../DisplayHardware/VirtualDisplaySurface.cpp | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 79 ++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 4 +- .../tests/unittests/CompositionTest.cpp | 34 ++++----- .../tests/unittests/DisplayTransactionTest.cpp | 31 ++++---- .../mock/system/window/MockNativeWindow.h | 1 - 11 files changed, 102 insertions(+), 190 deletions(-) diff --git a/libs/renderengine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp index e244a83c09..70a4322c5f 100644 --- a/libs/renderengine/gl/GLES20RenderEngine.cpp +++ b/libs/renderengine/gl/GLES20RenderEngine.cpp @@ -275,8 +275,6 @@ std::unique_ptr GLES20RenderEngine::create(int hwcFormat, // now figure out what version of GL did we actually get // NOTE: a dummy surface is not needed if KHR_create_context is supported - // TODO(alecmouri): don't create this surface if EGL_KHR_surfaceless_context - // is supported. EGLConfig dummyConfig = config; if (dummyConfig == EGL_NO_CONFIG) { @@ -303,10 +301,10 @@ std::unique_ptr GLES20RenderEngine::create(int hwcFormat, break; case GLES_VERSION_2_0: case GLES_VERSION_3_0: - engine = std::make_unique(featureFlags, display, config, ctxt, - dummy); + engine = std::make_unique(featureFlags); break; } + engine->setEGLHandles(display, config, ctxt); ALOGI("OpenGL ES informations:"); ALOGI("vendor : %s", extensions.getVendor()); @@ -316,6 +314,9 @@ std::unique_ptr GLES20RenderEngine::create(int hwcFormat, ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize()); ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims()); + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(display, dummy); + return engine; } @@ -358,13 +359,11 @@ EGLConfig GLES20RenderEngine::chooseEglConfig(EGLDisplay display, int format, bo return config; } -GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config, - EGLContext ctxt, EGLSurface dummy) +GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) : renderengine::impl::RenderEngine(featureFlags), - mEGLDisplay(display), - mEGLConfig(config), - mEGLContext(ctxt), - mDummySurface(dummy), + mEGLDisplay(EGL_NO_DISPLAY), + mEGLConfig(nullptr), + mEGLContext(EGL_NO_CONTEXT), mVpWidth(0), mVpHeight(0), mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) { @@ -637,6 +636,12 @@ void GLES20RenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) { // back to main framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Workaround for b/77935566 to force the EGL driver to release the + // screenshot buffer + setScissor(Rect::EMPTY_RECT); + clearWithColor(0.0, 0.0, 0.0, 0.0); + disableScissor(); } void GLES20RenderEngine::checkErrors() const { @@ -969,6 +974,12 @@ bool GLES20RenderEngine::needsXYZTransformMatrix() const { return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer; } +void GLES20RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) { + mEGLDisplay = display; + mEGLConfig = config; + mEGLContext = ctxt; +} + } // namespace gl } // namespace renderengine } // namespace android diff --git a/libs/renderengine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h index aebb319a99..148df2fbb4 100644 --- a/libs/renderengine/gl/GLES20RenderEngine.h +++ b/libs/renderengine/gl/GLES20RenderEngine.h @@ -47,8 +47,7 @@ public: static std::unique_ptr create(int hwcFormat, uint32_t featureFlags); static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); - GLES20RenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag - EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy); + GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag ~GLES20RenderEngine() override; std::unique_ptr createFramebuffer() override; @@ -121,12 +120,11 @@ private: // with PQ or HLG transfer function. bool isHdrDataSpace(const ui::Dataspace dataSpace) const; bool needsXYZTransformMatrix() const; - void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy); + void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt); EGLDisplay mEGLDisplay; EGLConfig mEGLConfig; EGLContext mEGLContext; - EGLSurface mDummySurface; GLuint mProtectedTexName; GLint mMaxViewportDims[2]; GLint mMaxTextureSize; diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 9abb040a9c..f168db9f7b 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -184,7 +184,6 @@ cc_defaults { "libhidltransport", "liblayers_proto", "liblog", - "libsync", "libtimestats_proto", "libutils", ], diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index d5b24ae56c..5342bcf0a5 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -35,8 +35,6 @@ #include #include #include -#include -#include #include #include #include @@ -223,7 +221,6 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) mDisplayToken(args.displayToken), mId(args.displayId), mNativeWindow(args.nativeWindow), - mGraphicBuffer(nullptr), mDisplaySurface(args.displaySurface), mSurface{std::move(args.renderSurface)}, mDisplayInstallOrientation(args.displayInstallOrientation), @@ -287,10 +284,6 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance); ANativeWindow* const window = mNativeWindow.get(); - - int status = native_window_api_connect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL); - ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status); - mDisplayWidth = ANativeWindow_getWidth(window); mDisplayHeight = ANativeWindow_getHeight(window); @@ -328,6 +321,7 @@ uint32_t DisplayDevice::getPageFlipCount() const { void DisplayDevice::flip() const { + mFlinger->getRenderEngine().checkErrors(); mPageFlipCount++; } @@ -362,71 +356,9 @@ status_t DisplayDevice::prepareFrame(HWComposer& hwc, return mDisplaySurface->prepareFrame(compositionType); } -sp DisplayDevice::dequeueBuffer() { - int fd; - ANativeWindowBuffer* buffer; - - status_t res = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd); - - if (res != NO_ERROR) { - ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d", - getDisplayName().c_str(), res); - // Return fast here as we can't do much more - any rendering we do - // now will just be wrong. - return mGraphicBuffer; - } - - ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].", - mGraphicBuffer->getNativeBuffer()->handle); - mGraphicBuffer = GraphicBuffer::from(buffer); - - // Block until the buffer is ready - // TODO(alecmouri): it's perhaps more appropriate to block renderengine so - // that the gl driver can block instead. - if (fd >= 0) { - sync_wait(fd, -1); - close(fd); - } - - return mGraphicBuffer; -} - -void DisplayDevice::queueBuffer(HWComposer& hwc) { +void DisplayDevice::swapBuffers(HWComposer& hwc) const { if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) { - // hasFlipClientTargetRequest could return true even if we haven't - // dequeued a buffer before. Try dequeueing one if we don't have a - // buffer ready. - if (mGraphicBuffer == nullptr) { - ALOGI("Attempting to queue a client composited buffer without one " - "previously dequeued for display [%s]. Attempting to dequeue " - "a scratch buffer now", - mDisplayName.c_str()); - // We shouldn't deadlock here, since mGraphicBuffer == nullptr only - // after a successful call to queueBuffer, or if dequeueBuffer has - // never been called. - dequeueBuffer(); - } - - if (mGraphicBuffer == nullptr) { - ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str()); - } else { - int fd = mBufferReady.release(); - - status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), fd); - if (res != NO_ERROR) { - ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res); - // We risk blocking on dequeueBuffer if the primary display failed - // to queue up its buffer, so crash here. - if (isPrimary()) { - LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res); - } else { - mNativeWindow->cancelBuffer(mNativeWindow.get(), - mGraphicBuffer->getNativeBuffer(), fd); - } - } - mGraphicBuffer = nullptr; - } + mSurface->swapBuffers(); } status_t result = mDisplaySurface->advanceFrame(); @@ -435,7 +367,7 @@ void DisplayDevice::queueBuffer(HWComposer& hwc) { } } -void DisplayDevice::onPresentDisplayCompleted() { +void DisplayDevice::onSwapBuffersCompleted() const { mDisplaySurface->onFrameCommitted(); } @@ -452,13 +384,6 @@ void DisplayDevice::setViewportAndProjection() const { mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0); } -void DisplayDevice::finishBuffer() { - mBufferReady = mFlinger->getRenderEngine().flush(); - if (mBufferReady.get() < 0) { - mFlinger->getRenderEngine().finish(); - } -} - const sp& DisplayDevice::getClientTargetAcquireFence() const { return mDisplaySurface->getClientTargetAcquireFence(); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 560a9588b5..bcd3330cf2 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -28,14 +28,13 @@ #include #include #include -#include #include #include #include #include #include -#include #include +#include #include #include @@ -147,13 +146,10 @@ public: ui::Dataspace* outDataspace, ui::ColorMode* outMode, ui::RenderIntent* outIntent) const; - // Queues the drawn buffer for consumption by HWC. - void queueBuffer(HWComposer& hwc); - // Allocates a buffer as scratch space for GPU composition - sp dequeueBuffer(); + void swapBuffers(HWComposer& hwc) const; // called after h/w composer has completed its set() call - void onPresentDisplayCompleted(); + void onSwapBuffersCompleted() const; Rect getBounds() const { return Rect(mDisplayWidth, mDisplayHeight); @@ -164,11 +160,6 @@ public: const std::string& getDisplayName() const { return mDisplayName; } bool makeCurrent() const; - // Acquires a new buffer for GPU composition. - void readyNewBuffer(); - // Marks the current buffer has finished, so that it can be presented and - // swapped out. - void finishBuffer(); void setViewportAndProjection() const; const sp& getClientTargetAcquireFence() const; @@ -213,12 +204,7 @@ private: // ANativeWindow this display is rendering into sp mNativeWindow; - // Current buffer that this display can render to. - sp mGraphicBuffer; sp mDisplaySurface; - // File descriptor indicating that mGraphicBuffer is ready for display, i.e. - // that drawing to the buffer is now complete. - base::unique_fd mBufferReady; std::unique_ptr mSurface; int mDisplayWidth; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 5f3fcd6e88..27d3dc5609 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -107,6 +107,8 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); sink->setAsyncMode(true); + IGraphicBufferProducer::QueueBufferOutput output; + mSource[SOURCE_SCRATCH]->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &output); } VirtualDisplaySurface::~VirtualDisplaySurface() { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3f3c497fc7..25c60fe3d3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -677,6 +676,10 @@ void SurfaceFlinger::init() { LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()), "Internal display is disconnected."); + // make the default display GLContext current so that we can create textures + // when creating Layers (which may happens before we render something) + display->makeCurrent(); + if (useVrFlinger) { auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) { // This callback is called from the vr flinger dispatch thread. We @@ -1406,6 +1409,7 @@ void SurfaceFlinger::resetDisplayState() { // mCurrentState and mDrawingState and re-apply all changes when we make the // transition. mDrawingState.displays.clear(); + getRenderEngine().resetCurrentSurface(); mDisplays.clear(); } @@ -1715,7 +1719,7 @@ void SurfaceFlinger::doDebugFlashRegions(const sp& display, bool auto& engine(getRenderEngine()); engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1); - display->queueBuffer(getHwComposer()); + display->swapBuffers(getHwComposer()); } } @@ -2190,7 +2194,8 @@ void SurfaceFlinger::postFramebuffer(const sp& display) if (displayId) { getHwComposer().presentAndGetReleaseFences(*displayId); } - display->onPresentDisplayCompleted(); + display->onSwapBuffersCompleted(); + display->makeCurrent(); for (auto& layer : display->getVisibleLayersSortedByZ()) { sp releaseFence = Fence::NO_FENCE; @@ -2343,11 +2348,16 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( std::unique_ptr renderSurface = getRenderEngine().createSurface(); renderSurface->setCritical(isInternalDisplay); renderSurface->setAsync(state.isVirtual()); + renderSurface->setNativeWindow(nativeWindow.get()); creationArgs.renderSurface = std::move(renderSurface); // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. We have to do this - // here, in case the display is composed entirely by HWC. + // in two places: + // * Here, in case the display is composed entirely by HWC. + // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the + // window's swap interval in eglMakeCurrent, so they'll override the + // interval we set here. if (state.isVirtual()) { nativeWindow->setSwapInterval(nativeWindow.get(), 0); } @@ -2407,6 +2417,12 @@ void SurfaceFlinger::processDisplayChangesLocked() { const auto externalDisplayId = getExternalDisplayId(); // in drawing state but not in current state + // Call makeCurrent() on the primary display so we can + // be sure that nothing associated with this display + // is current. + if (const auto defaultDisplay = getDefaultDisplayDeviceLocked()) { + defaultDisplay->makeCurrent(); + } if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) { display->disconnect(getHwComposer()); } @@ -2957,7 +2973,7 @@ void SurfaceFlinger::invalidateHwcGeometry() mGeometryInvalid = true; } -void SurfaceFlinger::doDisplayComposition(const sp& display, +void SurfaceFlinger::doDisplayComposition(const sp& display, const Region& inDirtyRegion) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to @@ -2972,10 +2988,10 @@ void SurfaceFlinger::doDisplayComposition(const sp& display, if (!doComposeSurfaces(display)) return; // swap buffers (presentation) - display->queueBuffer(getHwComposer()); + display->swapBuffers(getHwComposer()); } -bool SurfaceFlinger::doComposeSurfaces(const sp& display) { +bool SurfaceFlinger::doComposeSurfaces(const sp& display) { ALOGV("doComposeSurfaces"); const Region bounds(display->bounds()); @@ -2988,31 +3004,9 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& display) { bool applyColorMatrix = false; bool needsEnhancedColorMatrix = false; - // Framebuffer will live in this scope for GPU composition. - std::unique_ptr fbo; - if (hasClientComposition) { ALOGV("hasClientComposition"); - sp buf = display->dequeueBuffer(); - - if (buf == nullptr) { - ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " - "client composition for this frame", - display->getDisplayName().c_str()); - return false; - } - - // Bind the framebuffer in this scope. - fbo = std::make_unique(getRenderEngine(), - buf->getNativeBuffer()); - - if (fbo->getStatus() != NO_ERROR) { - ALOGW("Binding buffer for display [%s] failed with status: %d", - display->getDisplayName().c_str(), fbo->getStatus()); - return false; - } - Dataspace outputDataspace = Dataspace::UNKNOWN; if (display->hasWideColorGamut()) { outputDataspace = display->getCompositionDataSpace(); @@ -3041,7 +3035,18 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& display) { colorMatrix *= mEnhancedSaturationMatrix; } - display->setViewportAndProjection(); + if (!display->makeCurrent()) { + ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s", + display->getDisplayName().c_str()); + getRenderEngine().resetCurrentSurface(); + + // |mStateLock| not needed as we are on the main thread + const auto defaultDisplay = getDefaultDisplayDeviceLocked(); + if (!defaultDisplay || !defaultDisplay->makeCurrent()) { + ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting."); + } + return false; + } // Never touch the framebuffer if we don't have any framebuffer layers if (hasDeviceComposition) { @@ -3134,15 +3139,11 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& display) { firstLayer = false; } - // Perform some cleanup steps if we used client composition. - if (hasClientComposition) { - getRenderEngine().setColorTransform(mat4()); - getBE().mRenderEngine->disableScissor(); - display->finishBuffer(); - // Clear out error flags here so that we don't wait until next - // composition to log. - getRenderEngine().checkErrors(); - } + // Clear color transform matrix at the end of the frame. + getRenderEngine().setColorTransform(mat4()); + + // disable scissor at the end of the frame + getBE().mRenderEngine->disableScissor(); return true; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f5218b175a..6ffe0259d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -721,10 +721,10 @@ private: void doDebugFlashRegions(const sp& display, bool repaintEverything); void doTracing(const char* where); void logLayerStats(); - void doDisplayComposition(const sp& display, const Region& dirtyRegion); + void doDisplayComposition(const sp& display, const Region& dirtyRegion); // This fails if using GL and the surface has been destroyed. - bool doComposeSurfaces(const sp& display); + bool doComposeSurfaces(const sp& display); void postFramebuffer(const sp& display); void postFrame(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 6d3e71562d..ab1b2522cf 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -46,7 +46,6 @@ using testing::_; using testing::AtLeast; using testing::ByMove; using testing::DoAll; -using testing::Invoke; using testing::IsNull; using testing::Mock; using testing::NotNull; @@ -143,9 +142,6 @@ public: renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface(); mock::NativeWindow* mNativeWindow = new mock::NativeWindow(); - sp mBuffer = new GraphicBuffer(); - ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer(); - mock::EventThread* mEventThread = new mock::EventThread(); mock::EventControlThread* mEventControlThread = new mock::EventControlThread(); @@ -270,9 +266,13 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return()); EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true)); - EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() { - return base::unique_fd(0); - })); + EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface))) + .WillOnce(Return(true)); + EXPECT_CALL(*test->mRenderEngine, + setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, + Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), + ui::Transform::ROT_0)) + .Times(1); EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1); EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1); @@ -323,6 +323,8 @@ struct BaseDisplayVariant { static void setupHwcCompositionCallExpectations(CompositionTest* test) { EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1); + + EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1); } static void setupRECompositionCallExpectations(CompositionTest* test) { @@ -342,18 +344,12 @@ struct BaseDisplayVariant { setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT, Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), ui::Transform::ROT_0)) - .Times(1); - EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true)); - EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true)); - EXPECT_CALL(*test->mRenderEngine, createFramebuffer()) - .WillOnce(Return( - ByMove(std::unique_ptr(test->mReFrameBuffer)))); - EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1); - EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1); - EXPECT_CALL(*test->mNativeWindow, queueBuffer(_, _)).WillOnce(Return(0)); - EXPECT_CALL(*test->mNativeWindow, dequeueBuffer(_, _)) - .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1), - Return(0))); + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface))) + .WillOnce(Return(true)) + .RetiresOnSaturation(); + EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1); } template diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 4923785a28..32fce677af 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -120,7 +120,6 @@ public: mock::EventThread* mEventThread = new mock::EventThread(); mock::EventControlThread* mEventControlThread = new mock::EventControlThread(); sp mNativeWindow = new mock::NativeWindow(); - sp mBuffer = new GraphicBuffer(); // These mocks are created by the test, but are destroyed by SurfaceFlinger // by virtue of being stored into a std::unique_ptr. However we still need @@ -341,6 +340,7 @@ struct DisplayVariant { static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow()) .WillOnce(Return(test->mNativeWindow)); + EXPECT_CALL(*test->mNativeWindow, perform(19)).WillRepeatedly(Return(NO_ERROR)); // For simplicity, we only expect to create a single render surface for // each test. @@ -349,15 +349,17 @@ struct DisplayVariant { EXPECT_CALL(*test->mRenderEngine, createSurface()) .WillOnce(Return(ByMove( std::unique_ptr(test->mRenderSurface)))); + + // Creating a DisplayDevice requires getting default dimensions from the + // native window. EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0))); EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0))); - // Creating a DisplayDevice requires getting default dimensions from the - // native window. EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast(ASYNC))).Times(1); EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast(CRITICAL))).Times(1); + EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1); } static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) { @@ -1068,6 +1070,9 @@ TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) { // The call disable vsyncs EXPECT_CALL(*mEventControlThread, setVsyncEnabled(false)).Times(1); + // The call clears the current render engine surface + EXPECT_CALL(*mRenderEngine, resetCurrentSurface()); + // The call ends any display resyncs EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1); @@ -1127,7 +1132,6 @@ public: .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0))); EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0))); - EXPECT_CALL(*mNativeWindow, perform(13)).Times(1); auto displayDevice = mInjector.inject(); displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace, @@ -1721,6 +1725,7 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) { EXPECT_CALL(*surface, setAsyncMode(true)).Times(1); + EXPECT_CALL(*mProducer, connect(_, _, _, _)).Times(1); EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1); Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this); @@ -1945,17 +1950,10 @@ TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) { auto nativeWindow = new mock::NativeWindow(); auto displaySurface = new mock::DisplaySurface(); auto renderSurface = new renderengine::mock::Surface(); - sp buf = new GraphicBuffer(); auto display = Case::Display::makeFakeExistingDisplayInjector(this); display.setNativeWindow(nativeWindow); display.setDisplaySurface(displaySurface); display.setRenderSurface(std::unique_ptr(renderSurface)); - // Setup injection expections - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0))); - EXPECT_CALL(*nativeWindow, perform(13)).Times(1); display.inject(); // There is a change to the viewport state @@ -1967,7 +1965,9 @@ TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) { // -------------------------------------------------------------------- // Call Expectations + EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1); EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1); + EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1); // -------------------------------------------------------------------- // Invocation @@ -1989,17 +1989,10 @@ TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) { auto nativeWindow = new mock::NativeWindow(); auto displaySurface = new mock::DisplaySurface(); auto renderSurface = new renderengine::mock::Surface(); - sp buf = new GraphicBuffer(); auto display = Case::Display::makeFakeExistingDisplayInjector(this); display.setNativeWindow(nativeWindow); display.setDisplaySurface(displaySurface); display.setRenderSurface(std::unique_ptr(renderSurface)); - // Setup injection expections - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0))); - EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _)) - .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0))); - EXPECT_CALL(*nativeWindow, perform(13)).Times(1); display.inject(); // There is a change to the viewport state @@ -2011,7 +2004,9 @@ TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) { // -------------------------------------------------------------------- // Call Expectations + EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1); EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1); + EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h index 4950a4b9e2..561fd5869e 100644 --- a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h +++ b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h @@ -36,7 +36,6 @@ public: MOCK_METHOD1(queueBuffer_DEPRECATED, int(struct ANativeWindowBuffer*)); MOCK_CONST_METHOD2(query, int(int, int*)); MOCK_METHOD1(perform, int(int)); - MOCK_METHOD2(perform, int(int, int)); MOCK_METHOD1(cancelBuffer_DEPRECATED, int(struct ANativeWindowBuffer*)); MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*)); MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int)); -- cgit v1.2.3-59-g8ed1b From fec719560e1beb6b65873422d1f0924c858babf0 Mon Sep 17 00:00:00 2001 From: Rob Carr Date: Thu, 29 Nov 2018 13:08:54 -0800 Subject: IInputFlinger: setInputWindows is one-way Since we call from SurfaceFlinger to the system-server we want to avoid blocking. Bug: 120225258 Test: Existing tests pass. Change-Id: I7ef47bff5bb583798efbcb3753158d9520de52b0 (cherry picked from commit 2ccbd6eed75bed7b5ae4db478ffe4e36d067cc88) --- libs/input/IInputFlinger.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp index 477e54e708..139570a5fd 100644 --- a/libs/input/IInputFlinger.cpp +++ b/libs/input/IInputFlinger.cpp @@ -38,7 +38,8 @@ public: for (const auto& info : inputInfo) { info.write(data); } - remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply); + remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply, + IBinder::FLAG_ONEWAY); } virtual void registerInputChannel(const sp& channel) { -- cgit v1.2.3-59-g8ed1b From d702c3ab6e1621d1a1baa0954c8efe9d42a53a18 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 3 Dec 2018 15:10:36 -0600 Subject: Check that window handle is visible Ensure inputwindowhandle is visible before letting it receive focused events. This is a temporary fix. The issue currently is that two windows can have focus at the same time. The input consumer is made not visible, but focus is never removed from it. Bug: 120187922 Test: tested on taimen. To reproduce: enable quickstep: in settings, type "swipe", then the last setting "swipe up on home button" choose "enable". Next, open an app (clock or messages, for example). Open settings app. In settings, navigate at least 1 depth into a subsetting. Next, use the wheel to select the first app that was open. Try to click back button or use volume keys, both should work. Change-Id: I5730a7c7e0740fe6db2d4d581837c1af8d8740fd (cherry picked from commit 49ee32334ad04d2e3bbee6e9216882eef8807bf2) --- services/inputflinger/InputDispatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index bea4f911d9..12d91bbd68 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -3093,7 +3093,7 @@ void InputDispatcher::setInputWindows(const Vector>& input continue; } - if (windowHandle->getInfo()->hasFocus) { + if (windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) { newFocusedWindowHandle = windowHandle; } if (windowHandle == mLastHoverWindowHandle) { -- cgit v1.2.3-59-g8ed1b From 34bf94778b0936a3d77c0c282d8617f81231ebf9 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 5 Dec 2018 07:27:23 -0800 Subject: Input: Handle parent surface crops 1/2 - Surface Insets are set to offset the client content and draw a border around the client surface (such as shadows in dialogs). Inputs sent to the client are offset such that 0,0 is the start of the client content. When accounting for surface insets, check if the surface is already cropped by a parent so that the input offset is not set twice. - Restrict the touchable region to the input frame bounds. Test: Open event in calendar. Try to close the event. The event is a dialog and draws shadows. Test: Open app selector in secondary split screen. Ensure input does not go to primary split screen window. Bug: 120413463, 120460606 Change-Id: I0d519f9eb381664b1e71a924b13419dcc1170ba1 (cherry picked from commit 8033a496f29ed76c361822e0d2f11beaea22a27b) --- libs/ui/Rect.cpp | 8 ++++++++ libs/ui/include/ui/Rect.h | 7 ++++++- services/surfaceflinger/Layer.cpp | 27 ++++++++++++++++++++------- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp index d8702e5755..045db31087 100644 --- a/libs/ui/Rect.cpp +++ b/libs/ui/Rect.cpp @@ -72,6 +72,14 @@ Rect& Rect::offsetBy(int32_t x, int32_t y) { return *this; } +Rect& Rect::inset(int32_t left, int32_t top, int32_t right, int32_t bottom) { + this->left += left; + this->top += top; + this->right -= right; + this->bottom -= bottom; + return *this; +} + const Rect Rect::operator +(const Point& rhs) const { const Rect result(left + rhs.x, top + rhs.y, right + rhs.x, bottom + rhs.y); return result; diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h index 0bec0b7f78..9edb510ee9 100644 --- a/libs/ui/include/ui/Rect.h +++ b/libs/ui/include/ui/Rect.h @@ -120,7 +120,7 @@ public: right = rb.x; bottom = rb.y; } - + // the following 4 functions return the 4 corners of the rect as Point Point leftTop() const { return Point(left, top); @@ -175,6 +175,11 @@ public: Rect& offsetTo(int32_t x, int32_t y); Rect& offsetBy(int32_t x, int32_t y); + /** + * Insets the rectangle on all sides specified by the insets. + */ + Rect& inset(int32_t left, int32_t top, int32_t right, int32_t bottom); + bool intersect(const Rect& with, Rect* result) const; // Create a new Rect by transforming this one using a graphics HAL diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 15e416ac2a..f53ffae570 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2121,10 +2121,6 @@ bool Layer::isRemovedFromCurrentState() const { InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) { InputWindowInfo info = mDrawingState.inputInfo; - info.frameLeft = screenBounds.left + info.surfaceInset; - info.frameTop = screenBounds.top + info.surfaceInset; - info.frameRight = screenBounds.right - info.surfaceInset; - info.frameBottom = screenBounds.bottom - info.surfaceInset; ui::Transform t = getTransform(); const float xScale = t.sx(); @@ -2135,9 +2131,26 @@ InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) { info.touchableRegion.scaleSelf(xScale, yScale); } - info.touchableRegion = info.touchableRegion.translate( - screenBounds.left, - screenBounds.top); + // Transform layer size to screen space and inset it by surface insets. + Rect layerBounds = getCroppedBufferSize(getDrawingState()); + layerBounds = t.transform(layerBounds); + layerBounds.inset(info.surfaceInset, info.surfaceInset, info.surfaceInset, info.surfaceInset); + + // Intersect with screen bounds to shrink the frame by the surface insets. The surface insets + // are not set on the screen bounds directly since the surface inset region may already be + // cropped by a parent layer. + Rect frame; + screenBounds.intersect(layerBounds, &frame); + + info.frameLeft = frame.left; + info.frameTop = frame.top; + info.frameRight = frame.right; + info.frameBottom = frame.bottom; + + // Position the touchable region relative to frame screen location and restrict it to frame + // bounds. + info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop); + info.touchableRegion = info.touchableRegion.intersect(frame); info.visible = isVisible(); return info; } -- cgit v1.2.3-59-g8ed1b From 069560f6124029c6329acb02df4abe04de58b604 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 6 Dec 2018 13:54:33 -0800 Subject: Input: Let WM compute touchable region 1/2 - For modal windows let WM define the touchable region. This fixes a regression introduced by ag/5700485 where input was sent to background windows. - When calculating input surface position, ignore the transparent region so that we do not incorrectly offset the input. This fixes and issue with input offset in AutoDesk drawing app. Bug: 120615996, 120612739, 120585467 Test: Manual testing with apps listed in bugs. Automated tests to follow Change-Id: I906f1396ccc0c76f602a9903e696eedfc026f7c2 (cherry picked from commit f590f113eee4b24de86bef71c92c1f7fd206e0ac) --- services/surfaceflinger/Layer.cpp | 7 ++++--- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 5 ++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f53ffae570..aeb4a5d230 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -289,8 +289,10 @@ static FloatRect reduce(const FloatRect& win, const Region& exclude) { return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect(); } -Rect Layer::computeScreenBounds() const { - FloatRect bounds = computeBounds(); +Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const { + const State& s(getDrawingState()); + Region transparentRegion = reduceTransparentRegion ? getActiveTransparentRegion(s) : Region(); + FloatRect bounds = computeBounds(transparentRegion); ui::Transform t = getTransform(); // Transform to screen space. bounds = t.transform(bounds); @@ -2150,7 +2152,6 @@ InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) { // Position the touchable region relative to frame screen location and restrict it to frame // bounds. info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop); - info.touchableRegion = info.touchableRegion.intersect(frame); info.visible = isVisible(); return info; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 6ea80c7ab4..e5ce3d34f3 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -616,7 +616,7 @@ public: ssize_t removeChild(const sp& layer); sp getParent() const { return mCurrentParent.promote(); } bool hasParent() const { return getParent() != nullptr; } - Rect computeScreenBounds() const; + Rect computeScreenBounds(bool reduceTransparentRegion = true) const; bool setChildLayer(const sp& childLayer, int32_t z); bool setChildRelativeLayer(const sp& childLayer, const sp& relativeToHandle, int32_t relativeZ); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0bda020a8a..d9b9364030 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2753,7 +2753,10 @@ void SurfaceFlinger::updateInputWindows() { mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (layer->hasInput()) { - inputHandles.add(layer->fillInputInfo(layer->computeScreenBounds())); + // When calculating the screen bounds we ignore the transparent region since it may + // result in an unwanted offset. + inputHandles.add(layer->fillInputInfo( + layer->computeScreenBounds(false /* reduceTransparentRegion */))); } }); mInputFlinger->setInputWindows(inputHandles); -- cgit v1.2.3-59-g8ed1b From e8688907f20426fd3b9b432aa62f0d2817b7b258 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Thu, 10 Jan 2019 00:25:41 +0000 Subject: Revert "Enable ANGLE-for-Android rule processing again" This reverts commit 6d24de491e07a68526bbf760f2d2df2a7a756ea8. Reason for revert: b/122509524 Random bluetooth crash observed in QP1A.190108.001 Change-Id: Ib10d2b58822ba0895160dda5f4d2093672af091b (cherry picked from commit 6a5f97c212c093eefa766471a6e22166707ac0dd) --- libs/graphicsenv/GraphicsEnv.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 660e3c3ca8..9dc7431714 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -284,7 +284,16 @@ void GraphicsEnv::updateUseAngle() { } else { // The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily // load ANGLE and call the updatable opt-in/out logic: - void* featureSo = loadLibrary("feature_support"); + + // Check if ANGLE is enabled. Workaround for several bugs: + // b/119305693 b/119322355 b/119305887 + // Something is not working correctly in the feature library + char prop[PROPERTY_VALUE_MAX]; + property_get("debug.angle.enable", prop, "0"); + void* featureSo = nullptr; + if (atoi(prop)) { + featureSo = loadLibrary("feature_support"); + } if (featureSo) { ALOGV("loaded ANGLE's opt-in/out logic from namespace"); mUseAngle = checkAngleRules(featureSo); -- cgit v1.2.3-59-g8ed1b From a4b33bb9a6d9fe3f54a52d52818c3e6c267fa7b2 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Thu, 10 Jan 2019 00:25:41 +0000 Subject: Revert "Enable ANGLE-for-Android rule processing again" This reverts commit 6d24de491e07a68526bbf760f2d2df2a7a756ea8. Reason for revert: b/122509524 Random bluetooth crash observed in QP1A.190108.001 Change-Id: Ib10d2b58822ba0895160dda5f4d2093672af091b (cherry picked from commit 6a5f97c212c093eefa766471a6e22166707ac0dd) --- libs/graphicsenv/GraphicsEnv.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 660e3c3ca8..9dc7431714 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -284,7 +284,16 @@ void GraphicsEnv::updateUseAngle() { } else { // The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily // load ANGLE and call the updatable opt-in/out logic: - void* featureSo = loadLibrary("feature_support"); + + // Check if ANGLE is enabled. Workaround for several bugs: + // b/119305693 b/119322355 b/119305887 + // Something is not working correctly in the feature library + char prop[PROPERTY_VALUE_MAX]; + property_get("debug.angle.enable", prop, "0"); + void* featureSo = nullptr; + if (atoi(prop)) { + featureSo = loadLibrary("feature_support"); + } if (featureSo) { ALOGV("loaded ANGLE's opt-in/out logic from namespace"); mUseAngle = checkAngleRules(featureSo); -- cgit v1.2.3-59-g8ed1b From 971db45dcd70a25ae4dda062594581cf02c27da0 Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Thu, 28 Feb 2019 15:53:59 +0000 Subject: Revert "Caching between SF and HWC for BufferStateLayers" This reverts commit b28f007e51fb84ff78ce8b053d80efb0efdbce20. Reason for revert: Causing pre-submit failure b/126704033 Change-Id: I17c99cd410b3fa3825d01fedd21a52451368b5c0 (cherry picked from commit 5723fbda94dc6c8ecc444360dc2de487585daa78) --- services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 9 +- .../compositionengine/impl/HwcBufferCache.h | 22 ++--- .../CompositionEngine/src/HwcBufferCache.cpp | 40 +++----- .../CompositionEngine/tests/HwcBufferCacheTest.cpp | 102 +++++++++------------ .../DisplayHardware/FramebufferSurface.cpp | 6 +- .../DisplayHardware/VirtualDisplaySurface.cpp | 3 +- 7 files changed, 71 insertions(+), 113 deletions(-) diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 18b0d58b34..215dea1ee1 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -366,7 +366,7 @@ void BufferQueueLayer::setHwcLayerBuffer(const sp& display) uint32_t hwcSlot = 0; sp hwcBuffer; (*outputLayer->editState().hwc) - .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer); + .hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer); auto acquireFence = mConsumer->getCurrentFence(); auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index a6c090cfd8..f6b69ebccb 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -565,17 +565,14 @@ status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) { void BufferStateLayer::setHwcLayerBuffer(const sp& display) { const auto outputLayer = findOutputLayerForDisplay(display); LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc); - auto& hwcInfo = *outputLayer->editState().hwc; - auto& hwcLayer = hwcInfo.hwcLayer; + auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer; const State& s(getDrawingState()); - // obtain slot + // TODO(marissaw): support more than one slot uint32_t hwcSlot = 0; - sp buffer; - hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer); - auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence); + auto error = hwcLayer->setBuffer(hwcSlot, s.buffer, s.acquireFence); if (error != HWC2::Error::None) { ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), s.buffer->handle, to_string(error).c_str(), static_cast(error)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h index 3b4f6e4a88..b45de5a619 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h @@ -19,7 +19,6 @@ #include #include -#include #include namespace android { @@ -40,28 +39,19 @@ namespace compositionengine::impl { class HwcBufferCache { public: HwcBufferCache(); - // Given a buffer, return the HWC cache slot and + + // Given a buffer queue slot and buffer, return the HWC cache slot and // buffer to be sent to HWC. // // outBuffer is set to buffer when buffer is not in the HWC cache; // otherwise, outBuffer is set to nullptr. - void getHwcBuffer(const sp& buffer, uint32_t* outSlot, + void getHwcBuffer(int slot, const sp& buffer, uint32_t* outSlot, sp* outBuffer); -protected: - int getSlot(const sp& buffer); - int getLeastRecentlyUsedSlot(); - uint64_t getCounter(); - private: - // an array where the index corresponds to a slot and the value corresponds to a (counter, - // buffer) pair. "counter" is a unique value that indicates the last time this slot was updated - // or used and allows us to keep track of the least-recently used buffer. - std::pair> mBuffers[BufferQueue::NUM_BUFFER_SLOTS]; - - // The cache increments this counter value when a slot is updated or used. - // Used to track the least recently-used buffer - uint64_t mCounter = 1; + // a vector as we expect "slot" to be in the range of [0, 63] (that is, + // less than BufferQueue::NUM_BUFFER_SLOTS). + std::vector> mBuffers; }; } // namespace compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp index 8177c7f25d..6f340b96d0 100644 --- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp @@ -21,45 +21,31 @@ namespace android::compositionengine::impl { HwcBufferCache::HwcBufferCache() { - std::fill(std::begin(mBuffers), std::end(mBuffers), - std::pair>(0, nullptr)); + mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS); } -int HwcBufferCache::getSlot(const sp& buffer) { - // search for cached buffer first - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mBuffers[i].second == buffer) { - return i; - } - } - // use the least-recently used slot - return getLeastRecentlyUsedSlot(); -} +void HwcBufferCache::getHwcBuffer(int slot, const sp& buffer, uint32_t* outSlot, + sp* outBuffer) { + if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) { + // default to slot 0 + slot = 0; + } -int HwcBufferCache::getLeastRecentlyUsedSlot() { - auto iter = std::min_element(std::begin(mBuffers), std::end(mBuffers)); - return std::distance(std::begin(mBuffers), iter); -} + if (static_cast(slot) >= mBuffers.size()) { + mBuffers.resize(slot + 1); + } -void HwcBufferCache::getHwcBuffer(const sp& buffer, uint32_t* outSlot, - sp* outBuffer) { - *outSlot = getSlot(buffer); + *outSlot = slot; - auto& [currentCounter, currentBuffer] = mBuffers[*outSlot]; - if (currentBuffer == buffer) { + if (mBuffers[slot] == buffer) { // already cached in HWC, skip sending the buffer *outBuffer = nullptr; - currentCounter = getCounter(); } else { *outBuffer = buffer; // update cache - currentBuffer = buffer; - currentCounter = getCounter(); + mBuffers[slot] = buffer; } } -uint64_t HwcBufferCache::getCounter() { - return mCounter++; -} } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp index d4bbf6ddaa..f2a1aad2fc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp @@ -22,78 +22,60 @@ namespace android::compositionengine { namespace { -class TestableHwcBufferCache : public impl::HwcBufferCache { -public: - void getHwcBuffer(const sp& buffer, uint32_t* outSlot, - sp* outBuffer) { - HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer); - } - int getSlot(const sp& buffer) { return HwcBufferCache::getSlot(buffer); } - int getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); } -}; - class HwcBufferCacheTest : public testing::Test { public: ~HwcBufferCacheTest() override = default; - TestableHwcBufferCache mCache; + void testSlot(const int inSlot, const uint32_t expectedSlot) { + uint32_t outSlot; + sp outBuffer; + + // The first time, the output is the same as the input + mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer); + EXPECT_EQ(expectedSlot, outSlot); + EXPECT_EQ(mBuffer1, outBuffer); + + // The second time with the same buffer, the outBuffer is nullptr. + mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer); + EXPECT_EQ(expectedSlot, outSlot); + EXPECT_EQ(nullptr, outBuffer.get()); + + // With a new buffer, the outBuffer is the input. + mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer); + EXPECT_EQ(expectedSlot, outSlot); + EXPECT_EQ(mBuffer2, outBuffer); + + // Again, the second request with the same buffer sets outBuffer to nullptr. + mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer); + EXPECT_EQ(expectedSlot, outSlot); + EXPECT_EQ(nullptr, outBuffer.get()); + + // Setting a slot to use nullptr lookslike works, but note that + // the output values make it look like no new buffer is being set.... + mCache.getHwcBuffer(inSlot, sp(), &outSlot, &outBuffer); + EXPECT_EQ(expectedSlot, outSlot); + EXPECT_EQ(nullptr, outBuffer.get()); + } + + impl::HwcBufferCache mCache; sp mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; sp mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; }; -TEST_F(HwcBufferCacheTest, testSlot) { - uint32_t outSlot; - sp outBuffer; - - // The first time, the output is the same as the input - mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); - EXPECT_EQ(0, outSlot); - EXPECT_EQ(mBuffer1, outBuffer); - - // The second time with the same buffer, the outBuffer is nullptr. - mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); - EXPECT_EQ(0, outSlot); - EXPECT_EQ(nullptr, outBuffer.get()); - - // With a new buffer, the outBuffer is the input. - mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer); - EXPECT_EQ(1, outSlot); - EXPECT_EQ(mBuffer2, outBuffer); - - // Again, the second request with the same buffer sets outBuffer to nullptr. - mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer); - EXPECT_EQ(1, outSlot); - EXPECT_EQ(nullptr, outBuffer.get()); - - // Setting a slot to use nullptr lookslike works, but note that - // the output values make it look like no new buffer is being set.... - mCache.getHwcBuffer(sp(), &outSlot, &outBuffer); - EXPECT_EQ(2, outSlot); - EXPECT_EQ(nullptr, outBuffer.get()); +TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) { + testSlot(0, 0); } -TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) { - int slot; - uint32_t outSlot; - sp outBuffer; - - // fill up cache - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - sp buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; - mCache.getHwcBuffer(buf, &outSlot, &outBuffer); - EXPECT_EQ(buf, outBuffer); - EXPECT_EQ(i, outSlot); - } - - slot = mCache.getLeastRecentlyUsedSlot(); - EXPECT_EQ(0, slot); +TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) { + testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1); +} - mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); - EXPECT_EQ(0, outSlot); - EXPECT_EQ(mBuffer1, outBuffer); +TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) { + testSlot(-123, 0); +} - slot = mCache.getLeastRecentlyUsedSlot(); - EXPECT_EQ(1, slot); +TEST_F(HwcBufferCacheTest, cacheMapsInvalidBufferSlotToZero) { + testSlot(BufferQueue::INVALID_BUFFER_SLOT, 0); } } // namespace diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 775fb806b8..27812f7492 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -111,7 +111,8 @@ status_t FramebufferSurface::nextBuffer(uint32_t& outSlot, BufferItem item; status_t err = acquireBufferLocked(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer); + mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, + &outSlot, &outBuffer); return NO_ERROR; } else if (err != NO_ERROR) { ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); @@ -137,7 +138,8 @@ status_t FramebufferSurface::nextBuffer(uint32_t& outSlot, mCurrentFence = item.mFence; outFence = item.mFence; - mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer); + mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, + &outSlot, &outBuffer); outDataspace = static_cast(item.mDataSpace); status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace); if (result != NO_ERROR) { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 613dc777ee..1c2853a857 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -224,7 +224,8 @@ status_t VirtualDisplaySurface::advanceFrame() { if (fbBuffer != nullptr) { uint32_t hwcSlot = 0; sp hwcBuffer; - mHwcBufferCache.getHwcBuffer(fbBuffer, &hwcSlot, &hwcBuffer); + mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer, + &hwcSlot, &hwcBuffer); // TODO: Correctly propagate the dataspace from GL composition result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer, -- cgit v1.2.3-59-g8ed1b From a9ff1f92aeccb5b4031b53886e685273b8f5ba2d Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Thu, 4 Apr 2019 17:39:17 +0000 Subject: Revert "[SurfaceFlinger] Remove force GPU composition for layers with color transform." This reverts commit 37083d0515500a5e0cb24d082c72eba7f676dea5. Reason for revert: Breaks some display output Bug: 129945273 Merged-In: Ie0cdf9bd696ed4926fdd931d3c8a82fafd1a203f Change-Id: Ie0cdf9bd696ed4926fdd931d3c8a82fafd1a203f (cherry picked from commit 9055674c6c3cdf32207ccce77d27f4ea55c343f8) --- services/surfaceflinger/SurfaceFlinger.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5676c59834..33455b9d5a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1822,6 +1822,11 @@ void SurfaceFlinger::calculateWorkingSet() { layer->forceClientComposition(displayDevice); } + // TODO(b/111562338) remove when composer 2.3 is shipped. + if (layer->hasColorTransform()) { + layer->forceClientComposition(displayDevice); + } + if (layer->getRoundedCornerState().radius > 0.0f) { layer->forceClientComposition(displayDevice); } -- cgit v1.2.3-59-g8ed1b From c1b8077c48e9750e874d5ba89f77914b9c94b996 Mon Sep 17 00:00:00 2001 From: Sungtak Lee Date: Tue, 28 May 2019 13:38:23 -0700 Subject: Drop buffers for SurfaceFlinger properly Drop buffers restrictively when consumer is SurfaceFlinger. When both producer and consumer are controlled by app and timeout is not positive, drop buffers for SurfaceFlinger. Bug: 133214906 Change-Id: Ied102857673cbf36e51aac6abeea9abffbdcce67 (cherry picked from commit 45e9e0b133576dbfaf354ada2ab4179e9e4118b8) --- libs/gui/BufferQueueProducer.cpp | 2 +- libs/gui/include/gui/BufferQueueCore.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index c20c2f3dca..9c311a314f 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -886,7 +886,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mFence = acquireFence; item.mFenceTime = acquireFenceTime; item.mIsDroppable = mCore->mAsyncMode || - (!mCore->mLegacyBufferDrop && mConsumerIsSurfaceFlinger) || + (mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) || (mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) || (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot); item.mSurfaceDamage = surfaceDamage; diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 9c0ee99b59..690a85f395 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -233,7 +233,8 @@ private: // mLegacyBufferDrop indicates whether mQueueBufferCanDrop is in effect. // If this flag is set mQueueBufferCanDrop is working as explained. If not - // queueBuffer will not drop buffers unless consumer is SurfaceFlinger. + // queueBuffer will not drop buffers unless consumer is SurfaceFlinger and + // mQueueBufferCanDrop is set. bool mLegacyBufferDrop; // mDefaultBufferFormat can be set so it will override the buffer format -- cgit v1.2.3-59-g8ed1b