blob: ec1e0199f23618cecdb5bc3aa1b1ad80d8fd71dc [file] [log] [blame]
/*
* Copyright (C) 2023 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 <string.h> // strcmp
#include "EGL/egl.h"
#include "EGL/eglext.h"
#include "berberis/guest_abi/function_wrappers.h"
#include "berberis/guest_abi/guest_arguments.h"
#include "berberis/guest_abi/guest_params.h"
#include "berberis/guest_state/guest_state.h"
#include "berberis/proxy_loader/proxy_library_builder.h"
#include "berberis/runtime_primitives/known_guest_function_wrapper.h"
#include "berberis/runtime_primitives/runtime_library.h"
#include "berberis/base/tracing.h"
#include "native_bridge_proxy/android_api/libEGL/gl_common_defs.h"
namespace berberis {
namespace {
// glDebugMessageCallback
// glDebugMessageCallbackARB
// glDebugMessageCallbackKHR
void DoCustomTrampolineWithThunk_glDebugMessageCallback(HostCode callee, ProcessState* state) {
// Prototypes are not defined in EGL headers - even though library itself is supposed to know
// about these functions.
using Callback = void (*)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, void*, void*);
using PFN_callee = void (*)(Callback, void* Param);
PFN_callee callee_function = AsFuncPtr(callee);
auto [guest_callback, param] = GuestParamsValues<PFN_callee>(state);
Callback host_callback = WrapGuestFunction(guest_callback, "glDebugMessageCallback-callback");
callee_function(host_callback, param);
}
const auto DoCustomTrampolineWithThunk_glDebugMessageCallbackARB =
DoCustomTrampolineWithThunk_glDebugMessageCallback;
const auto DoCustomTrampolineWithThunk_glDebugMessageCallbackKHR =
DoCustomTrampolineWithThunk_glDebugMessageCallback;
void RunGuest_glDebugMessageCallback(GuestAddr pc, GuestArgumentBuffer* buf) {
// Prototypes are not defined in EGL headers - even though library itself is supposed to know
// about these functions.
using Callback = void (*)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, void*, void*);
using PFN_callee = void (*)(Callback, void* Param);
auto [callback, user_param] = HostArgumentsValues<PFN_callee>(buf);
WrapHostFunction(callback, "glDebugMessageCallback_DEBUGPROC");
RunGuestCall(pc, buf);
}
const auto RunGuest_glDebugMessageCallbackARB = RunGuest_glDebugMessageCallback;
const auto RunGuest_glDebugMessageCallbackKHR = RunGuest_glDebugMessageCallback;
void RunGuest_glGetPointerv(GuestAddr pc, GuestArgumentBuffer* buf) {
// Note: we don't need to do any tricks here yet since when Host function is converted to guest
// function it's actuall address doesn't change.
RunGuestCall(pc, buf);
}
const auto RunGuest_glGetPointervEXT = RunGuest_glGetPointerv;
const auto RunGuest_glGetPointervKHR = RunGuest_glGetPointerv;
// glGetPointerv
// glGetPointervEXT
// glGetPointervKHR
void DoCustomTrampolineWithThunk_glGetPointerv(HostCode callee, ProcessState* state) {
// Prototypes are not defined in EGL headers - even though library itself is supposed to know
// about these functions.
using PFN_callee = void (*)(uint32_t pname, void** params);
PFN_callee callee_function = AsFuncPtr(callee);
auto [pname, value] = GuestParamsValues<PFN_callee>(state);
callee_function(pname, value);
// This maybe any version of GLES, so compare to all possible key values in different versions.
if (pname == EGL_DEBUG_CALLBACK_KHR || pname == GLES2_AND_GLES3_DEBUG_CALLBACK_FUNCTION_KHR) {
// If callback is registered by guest, return the original guest address,
// since guest code may expect that (b/71363904).
GuestAddr guest_addr = SlowFindGuestAddrByWrapperAddr(*value);
if (guest_addr) {
*value = reinterpret_cast<void*>(guest_addr);
}
}
}
const auto DoCustomTrampolineWithThunk_glGetPointervEXT = DoCustomTrampolineWithThunk_glGetPointerv;
const auto DoCustomTrampolineWithThunk_glGetPointervKHR = DoCustomTrampolineWithThunk_glGetPointerv;
// Forward decl for android_api/egl/opengl_trampolines-inl.h:kOpenGLTrampolines.
void DoCustomTrampolineWithThunk_eglGetProcAddress(HostCode callee, ProcessState* state);
void RunGuest_eglGetProcAddress(GuestAddr pc, GuestArgumentBuffer* buf);
#include "opengl_trampolines-inl.h" // generated file NOLINT [build/include]
bool WrapEglHostFunction(const char* name, HostCode function) {
if (name == nullptr || function == nullptr) {
return false;
}
// TODO(eaeltsin): kOpenGLTrampolines are sorted, might use binary search!
for (const auto& t : kOpenGLTrampolines) {
if (strcmp(name, t.name) == 0) {
if (!t.marshal_and_call) {
break;
}
WrapHostFunctionImpl(function, t.marshal_and_call, name);
return true;
}
}
return false;
}
HostCode WrapEglGuestFunction(const char* name, GuestAddr function) {
if (name == nullptr || function == kNullGuestAddr) {
return nullptr;
}
// TODO(eaeltsin): kOpenGLTrampolines are sorted, might use binary search!
for (const auto& t : kOpenGLTrampolines) {
if (strcmp(name, t.name) == 0) {
if (!t.wrapper) {
break;
}
return t.wrapper(function);
}
}
return nullptr;
}
// void (*eglGetProcAddress(char const* procname))();
void DoCustomTrampolineWithThunk_eglGetProcAddress(HostCode callee, ProcessState* state) {
using PFN_callee = decltype(&eglGetProcAddress);
PFN_callee callee_function = AsFuncPtr(callee);
auto [proc_name] = GuestParamsValues<PFN_callee>(state);
auto&& [ret] = GuestReturnReference<PFN_callee>(state);
ret = callee_function(proc_name);
if (!ToGuestAddr(ret)) {
return;
}
if (!WrapEglHostFunction(proc_name, ToHostCode(ret))) {
// Host proc exists but we failed to wrap it. That's not fatal error because application
// may have a fallback code if certain GLES4-5-6 function is not available in our translator
// but is provided by drivers... but we want to know about it from logs anyway.
ALOGE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
TRACE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
ret = 0;
return;
}
}
void RunGuest_eglGetProcAddress(GuestAddr pc, GuestArgumentBuffer* buf) {
auto [proc_name] = HostArgumentsValues<decltype(eglGetProcAddress)>(buf);
RunGuestCall(pc, buf);
auto&& [result] = HostResultReference<decltype(eglGetProcAddress)>(buf);
if (!WrapEglHostFunction(proc_name, ToHostCode(GuestType(result)))) {
result = nullptr;
}
}
#if defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) && defined(__i386__)
#include "trampolines_arm_to_x86-inl.h" // generated file NOLINT [build/include]
#elif defined(NATIVE_BRIDGE_GUEST_ARCH_ARM64) && defined(__x86_64__)
#include "trampolines_arm64_to_x86_64-inl.h" // generated file NOLINT [build/include]
#elif defined(NATIVE_BRIDGE_GUEST_ARCH_RISCV64) && defined(__x86_64__)
#include "trampolines_riscv64_to_x86_64-inl.h" // generated file NOLINT [build/include]
#else
#error "Unknown guest/host arch combination"
#endif
using PFNEGLGETNEXTLAYERPROCADDRESSPROC = void* (*)(void*, const char*);
using EGLFuncPointer = __eglMustCastToProperFunctionPointerType;
using AndroidGLESLayer_InitializePtr =
EGLAPI void (*)(void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address);
using AndroidGLESLayer_GetProcAddressPtr = EGLAPI void* (*)(const char* funcName,
EGLFuncPointer next);
void DoCustomTrampolineWithThunk_eglNextLayerProcAddressProc(HostCode callee, ProcessState* state) {
auto [layer_id, proc_name] = GuestParamsValues<PFNEGLGETNEXTLAYERPROCADDRESSPROC>(state);
PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address = AsFuncPtr(callee);
auto&& [ret] = GuestReturnReference<PFNEGLGETNEXTLAYERPROCADDRESSPROC>(state);
ret = get_next_layer_proc_address(layer_id, proc_name);
if (!ret) {
return;
}
if (!WrapEglHostFunction(proc_name, ret)) {
// Host proc exists but we failed to wrap it.
// Host proc exists but we failed to wrap it. That's not fatal error because application
// may have a fallback code if certain GLES4-5-6 function is not available in our translator
// but is provided by drivers... but we want to know about it from logs anyway.
ALOGE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
TRACE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
ret = 0;
return;
}
}
void RunGuestAndroidGLESLayer_Initialize(GuestAddr pc, GuestArgumentBuffer* buf) {
auto [layer_id, get_next_layer_proc_address] =
HostArgumentsValues<AndroidGLESLayer_InitializePtr>(buf);
WrapHostFunctionImpl(reinterpret_cast<void*>(get_next_layer_proc_address),
DoCustomTrampolineWithThunk_eglNextLayerProcAddressProc,
"RunGuestAndroidGLESLayer_Initialize");
RunGuestCall(pc, buf);
}
void RunGuestAndroidGLESLayer_GetProcAddress(GuestAddr pc, GuestArgumentBuffer* buf) {
auto [proc_name, get_next_layer_proc_address] =
HostArgumentsValues<AndroidGLESLayer_GetProcAddressPtr>(buf);
auto&& [host_result] = HostResultReference<AndroidGLESLayer_GetProcAddressPtr>(buf);
if (get_next_layer_proc_address != nullptr &&
!WrapEglHostFunction(proc_name, ToHostCode(GuestType(get_next_layer_proc_address)))) {
host_result = const_cast<void*>(ToHostCode(GuestType(get_next_layer_proc_address)));
return;
}
RunGuestCall(pc, buf);
auto [guest_result] = GuestResultValue<AndroidGLESLayer_GetProcAddressPtr>(buf);
host_result = const_cast<void*>(WrapEglGuestFunction(proc_name, ToGuestAddr(guest_result)));
}
extern "C" void InitProxyLibrary(ProxyLibraryBuilder* builder) {
builder->Build("libEGL.so",
sizeof(kKnownTrampolines) / sizeof(kKnownTrampolines[0]),
kKnownTrampolines,
sizeof(kKnownVariables) / sizeof(kKnownVariables[0]),
kKnownVariables);
RegisterKnownGuestFunctionWrapper("AndroidGLESLayer_Initialize", [](GuestAddr pc) {
return WrapGuestFunctionImpl(pc,
kGuestFunctionWrapperSignature<AndroidGLESLayer_InitializePtr>,
RunGuestAndroidGLESLayer_Initialize,
"AndroidGLESLayer_Initialize");
});
RegisterKnownGuestFunctionWrapper("AndroidGLESLayer_GetProcAddress", [](GuestAddr pc) {
return WrapGuestFunctionImpl(pc,
kGuestFunctionWrapperSignature<AndroidGLESLayer_GetProcAddressPtr>,
RunGuestAndroidGLESLayer_GetProcAddress,
"AndroidGLESLayer_GetProcAddress");
});
}
} // namespace
} // namespace berberis