Merge "Webview overlay support" into sc-dev
This commit is contained in:
@@ -2595,6 +2595,16 @@ public final class SurfaceControl implements Parcelable {
|
||||
= sRegistry.registerNativeAllocation(this, mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction object that wraps a native peer.
|
||||
* @hide
|
||||
*/
|
||||
Transaction(long nativeObject) {
|
||||
mNativeObject = nativeObject;
|
||||
mFreeNativeResources =
|
||||
sRegistry.registerNativeAllocation(this, mNativeObject);
|
||||
}
|
||||
|
||||
private Transaction(Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
@@ -1355,6 +1355,16 @@ public final class ViewRootImpl implements ViewParent,
|
||||
}
|
||||
}
|
||||
|
||||
private void addASurfaceTransactionCallback() {
|
||||
HardwareRenderer.ASurfaceTransactionCallback callback = (nativeTransactionObj,
|
||||
nativeSurfaceControlObj,
|
||||
frameNr) -> {
|
||||
Transaction t = new Transaction(nativeTransactionObj);
|
||||
mergeWithNextTransaction(t, frameNr);
|
||||
};
|
||||
mAttachInfo.mThreadedRenderer.setASurfaceTransactionCallback(callback);
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
|
||||
mAttachInfo.mHardwareAccelerated = false;
|
||||
@@ -1391,6 +1401,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
|
||||
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
|
||||
attrs.getTitle().toString());
|
||||
addASurfaceTransactionCallback();
|
||||
mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
|
||||
updateColorModeIfNeeded(attrs.getColorMode());
|
||||
updateForceDarkMode();
|
||||
|
||||
@@ -753,6 +753,11 @@ public class HardwareRenderer {
|
||||
nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setASurfaceTransactionCallback(ASurfaceTransactionCallback callback) {
|
||||
nSetASurfaceTransactionCallback(mNativeProxy, callback);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setFrameCallback(FrameDrawingCallback callback) {
|
||||
nSetFrameCallback(mNativeProxy, callback);
|
||||
@@ -867,6 +872,23 @@ public class HardwareRenderer {
|
||||
session.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to receive callbacks when a transaction needs to be merged.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface ASurfaceTransactionCallback {
|
||||
/**
|
||||
* Invoked during a frame drawing.
|
||||
*
|
||||
* @param aSurfaceTranactionNativeObj the ASurfaceTransaction native object handle
|
||||
* @param aSurfaceControlNativeObj ASurfaceControl native object handle
|
||||
* @param frame The id of the frame being drawn.
|
||||
*/
|
||||
void onMergeTransaction(long aSurfaceTranactionNativeObj,
|
||||
long aSurfaceControlNativeObj, long frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to receive callbacks when a frame is being drawn.
|
||||
*
|
||||
@@ -1342,6 +1364,9 @@ public class HardwareRenderer {
|
||||
private static native void nSetPictureCaptureCallback(long nativeProxy,
|
||||
PictureCapturedCallback callback);
|
||||
|
||||
private static native void nSetASurfaceTransactionCallback(long nativeProxy,
|
||||
ASurfaceTransactionCallback callback);
|
||||
|
||||
private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
|
||||
|
||||
private static native void nSetFrameCompleteCallback(long nativeProxy,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <private/hwui/WebViewFunctor.h>
|
||||
#include "Properties.h"
|
||||
#include "renderthread/CanvasContext.h"
|
||||
#include "renderthread/RenderThread.h"
|
||||
|
||||
#include <log/log.h>
|
||||
@@ -115,11 +116,20 @@ void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
|
||||
ScopedCurrentFunctor currentFunctor(this);
|
||||
|
||||
WebViewOverlayData overlayParams = {
|
||||
// TODO:
|
||||
.overlaysMode = OverlaysMode::Disabled,
|
||||
.getSurfaceControl = currentFunctor.getSurfaceControl,
|
||||
.mergeTransaction = currentFunctor.mergeTransaction,
|
||||
};
|
||||
|
||||
if (!drawInfo.isLayer) {
|
||||
renderthread::CanvasContext* activeContext =
|
||||
renderthread::CanvasContext::getActiveContext();
|
||||
if (activeContext != nullptr) {
|
||||
ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
|
||||
if (rootSurfaceControl) overlayParams.overlaysMode = OverlaysMode::Enabled;
|
||||
}
|
||||
}
|
||||
|
||||
mCallbacks.gles.draw(mFunctor, mData, drawInfo, overlayParams);
|
||||
}
|
||||
|
||||
@@ -138,11 +148,12 @@ void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
|
||||
ScopedCurrentFunctor currentFunctor(this);
|
||||
|
||||
WebViewOverlayData overlayParams = {
|
||||
// TODO
|
||||
.overlaysMode = OverlaysMode::Disabled,
|
||||
.getSurfaceControl = currentFunctor.getSurfaceControl,
|
||||
.mergeTransaction = currentFunctor.mergeTransaction,
|
||||
};
|
||||
|
||||
// TODO, enable surface control once offscreen mode figured out
|
||||
mCallbacks.vk.draw(mFunctor, mData, params, overlayParams);
|
||||
}
|
||||
|
||||
@@ -166,15 +177,43 @@ void WebViewFunctor::destroyContext() {
|
||||
void WebViewFunctor::removeOverlays() {
|
||||
ScopedCurrentFunctor currentFunctor(this);
|
||||
mCallbacks.removeOverlays(mFunctor, mData, currentFunctor.mergeTransaction);
|
||||
if (mSurfaceControl) {
|
||||
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
|
||||
funcs.releaseFunc(mSurfaceControl);
|
||||
mSurfaceControl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ASurfaceControl* WebViewFunctor::getSurfaceControl() {
|
||||
// TODO
|
||||
return nullptr;
|
||||
ATRACE_NAME("WebViewFunctor::getSurfaceControl");
|
||||
if (mSurfaceControl != nullptr) return mSurfaceControl;
|
||||
|
||||
renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
|
||||
LOG_ALWAYS_FATAL_IF(activeContext == nullptr, "Null active canvas context!");
|
||||
|
||||
ASurfaceControl* rootSurfaceControl = activeContext->getSurfaceControl();
|
||||
LOG_ALWAYS_FATAL_IF(rootSurfaceControl == nullptr, "Null root surface control!");
|
||||
|
||||
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
|
||||
mSurfaceControl = funcs.createFunc(rootSurfaceControl, "Webview Overlay SurfaceControl");
|
||||
ASurfaceTransaction* transaction = funcs.transactionCreateFunc();
|
||||
funcs.transactionSetVisibilityFunc(transaction, mSurfaceControl,
|
||||
ASURFACE_TRANSACTION_VISIBILITY_SHOW);
|
||||
funcs.transactionApplyFunc(transaction);
|
||||
funcs.transactionDeleteFunc(transaction);
|
||||
return mSurfaceControl;
|
||||
}
|
||||
|
||||
void WebViewFunctor::mergeTransaction(ASurfaceTransaction* transaction) {
|
||||
// TODO
|
||||
ATRACE_NAME("WebViewFunctor::mergeTransaction");
|
||||
if (transaction == nullptr) return;
|
||||
renderthread::CanvasContext* activeContext = renderthread::CanvasContext::getActiveContext();
|
||||
LOG_ALWAYS_FATAL_IF(activeContext == nullptr, "Null active canvas context!");
|
||||
bool done = activeContext->mergeTransaction(transaction, mSurfaceControl);
|
||||
if (!done) {
|
||||
auto funcs = renderthread::RenderThread::getInstance().getASurfaceControlFunctions();
|
||||
funcs.transactionApplyFunc(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
WebViewFunctorManager& WebViewFunctorManager::instance() {
|
||||
|
||||
@@ -91,6 +91,7 @@ private:
|
||||
RenderMode mMode;
|
||||
bool mHasContext = false;
|
||||
bool mCreatedHandle = false;
|
||||
ASurfaceControl* mSurfaceControl = nullptr;
|
||||
};
|
||||
|
||||
class WebViewFunctorManager {
|
||||
|
||||
@@ -63,6 +63,10 @@ struct {
|
||||
jmethodID closeHintSession;
|
||||
} gHardwareRenderer;
|
||||
|
||||
struct {
|
||||
jmethodID onMergeTransaction;
|
||||
} gASurfaceTransactionCallback;
|
||||
|
||||
struct {
|
||||
jmethodID onFrameDraw;
|
||||
} gFrameDrawingCallback;
|
||||
@@ -509,6 +513,27 @@ static void android_view_ThreadedRenderer_setPictureCapturedCallbackJNI(JNIEnv*
|
||||
}
|
||||
}
|
||||
|
||||
static void android_view_ThreadedRenderer_setASurfaceTransactionCallback(
|
||||
JNIEnv* env, jobject clazz, jlong proxyPtr, jobject aSurfaceTransactionCallback) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
|
||||
if (!aSurfaceTransactionCallback) {
|
||||
proxy->setASurfaceTransactionCallback(nullptr);
|
||||
} else {
|
||||
JavaVM* vm = nullptr;
|
||||
LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
|
||||
auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(
|
||||
vm, env->NewGlobalRef(aSurfaceTransactionCallback));
|
||||
proxy->setASurfaceTransactionCallback(
|
||||
[globalCallbackRef](int64_t transObj, int64_t scObj, int64_t frameNr) {
|
||||
JNIEnv* env = getenv(globalCallbackRef->vm());
|
||||
env->CallVoidMethod(globalCallbackRef->object(),
|
||||
gASurfaceTransactionCallback.onMergeTransaction,
|
||||
static_cast<jlong>(transObj), static_cast<jlong>(scObj),
|
||||
static_cast<jlong>(frameNr));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env,
|
||||
jobject clazz, jlong proxyPtr, jobject frameCallback) {
|
||||
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
|
||||
@@ -762,8 +787,7 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"nSetName", "(JLjava/lang/String;)V", (void*)android_view_ThreadedRenderer_setName},
|
||||
{"nSetSurface", "(JLandroid/view/Surface;Z)V",
|
||||
(void*)android_view_ThreadedRenderer_setSurface},
|
||||
{"nSetSurfaceControl", "(JJ)V",
|
||||
(void*)android_view_ThreadedRenderer_setSurfaceControl},
|
||||
{"nSetSurfaceControl", "(JJ)V", (void*)android_view_ThreadedRenderer_setSurfaceControl},
|
||||
{"nPause", "(J)Z", (void*)android_view_ThreadedRenderer_pause},
|
||||
{"nSetStopped", "(JZ)V", (void*)android_view_ThreadedRenderer_setStopped},
|
||||
{"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha},
|
||||
@@ -804,6 +828,9 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"nSetPictureCaptureCallback",
|
||||
"(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V",
|
||||
(void*)android_view_ThreadedRenderer_setPictureCapturedCallbackJNI},
|
||||
{"nSetASurfaceTransactionCallback",
|
||||
"(JLandroid/graphics/HardwareRenderer$ASurfaceTransactionCallback;)V",
|
||||
(void*)android_view_ThreadedRenderer_setASurfaceTransactionCallback},
|
||||
{"nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
|
||||
(void*)android_view_ThreadedRenderer_setFrameCallback},
|
||||
{"nSetFrameCompleteCallback",
|
||||
@@ -866,6 +893,11 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) {
|
||||
GetStaticMethodIDOrDie(env, hardwareRenderer, "closeHintSession",
|
||||
"(Landroid/os/PerformanceHintManager$Session;)V");
|
||||
|
||||
jclass aSurfaceTransactionCallbackClass =
|
||||
FindClassOrDie(env, "android/graphics/HardwareRenderer$ASurfaceTransactionCallback");
|
||||
gASurfaceTransactionCallback.onMergeTransaction =
|
||||
GetMethodIDOrDie(env, aSurfaceTransactionCallbackClass, "onMergeTransaction", "(JJJ)V");
|
||||
|
||||
jclass frameCallbackClass = FindClassOrDie(env,
|
||||
"android/graphics/HardwareRenderer$FrameDrawingCallback");
|
||||
gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
|
||||
|
||||
@@ -56,6 +56,22 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
namespace renderthread {
|
||||
|
||||
namespace {
|
||||
class ScopedActiveContext {
|
||||
public:
|
||||
ScopedActiveContext(CanvasContext* context) { sActiveContext = context; }
|
||||
|
||||
~ScopedActiveContext() { sActiveContext = nullptr; }
|
||||
|
||||
static CanvasContext* getActiveContext() { return sActiveContext; }
|
||||
|
||||
private:
|
||||
static CanvasContext* sActiveContext;
|
||||
};
|
||||
|
||||
CanvasContext* ScopedActiveContext::sActiveContext = nullptr;
|
||||
} /* namespace */
|
||||
|
||||
CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
|
||||
RenderNode* rootRenderNode, IContextFactory* contextFactory) {
|
||||
auto renderType = Properties::getRenderPipelineType();
|
||||
@@ -473,6 +489,7 @@ void CanvasContext::draw() {
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedActiveContext activeContext(this);
|
||||
mCurrentFrameInfo->set(FrameInfoIndex::FrameInterval) =
|
||||
mRenderThread.timeLord().frameIntervalNanos();
|
||||
|
||||
@@ -880,6 +897,17 @@ SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) {
|
||||
return windowDirty;
|
||||
}
|
||||
|
||||
CanvasContext* CanvasContext::getActiveContext() {
|
||||
return ScopedActiveContext::getActiveContext();
|
||||
}
|
||||
|
||||
bool CanvasContext::mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control) {
|
||||
if (!mASurfaceTransactionCallback) return false;
|
||||
std::invoke(mASurfaceTransactionCallback, reinterpret_cast<int64_t>(transaction),
|
||||
reinterpret_cast<int64_t>(control), getFrameNumber());
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace renderthread */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
@@ -109,6 +109,8 @@ public:
|
||||
*/
|
||||
GrDirectContext* getGrContext() const { return mRenderThread.getGrContext(); }
|
||||
|
||||
ASurfaceControl* getSurfaceControl() const { return mSurfaceControl; }
|
||||
|
||||
// Won't take effect until next EGLSurface creation
|
||||
void setSwapBehavior(SwapBehavior swapBehavior);
|
||||
|
||||
@@ -201,6 +203,15 @@ public:
|
||||
static void onSurfaceStatsAvailable(void* context, ASurfaceControl* control,
|
||||
ASurfaceControlStats* stats);
|
||||
|
||||
void setASurfaceTransactionCallback(
|
||||
const std::function<void(int64_t, int64_t, int64_t)>& callback) {
|
||||
mASurfaceTransactionCallback = callback;
|
||||
}
|
||||
|
||||
bool mergeTransaction(ASurfaceTransaction* transaction, ASurfaceControl* control);
|
||||
|
||||
static CanvasContext* getActiveContext();
|
||||
|
||||
private:
|
||||
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
|
||||
IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
|
||||
@@ -296,6 +307,8 @@ private:
|
||||
|
||||
// If set to true, we expect that callbacks into onSurfaceStatsAvailable
|
||||
bool mExpectSurfaceStats = false;
|
||||
|
||||
std::function<void(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
|
||||
};
|
||||
|
||||
} /* namespace renderthread */
|
||||
|
||||
@@ -295,6 +295,12 @@ void RenderProxy::setPictureCapturedCallback(
|
||||
[this, cb = callback]() { mContext->setPictureCapturedCallback(cb); });
|
||||
}
|
||||
|
||||
void RenderProxy::setASurfaceTransactionCallback(
|
||||
const std::function<void(int64_t, int64_t, int64_t)>& callback) {
|
||||
mRenderThread.queue().post(
|
||||
[this, cb = callback]() { mContext->setASurfaceTransactionCallback(cb); });
|
||||
}
|
||||
|
||||
void RenderProxy::setFrameCallback(std::function<void(int64_t)>&& callback) {
|
||||
mDrawFrameTask.setFrameCallback(std::move(callback));
|
||||
}
|
||||
|
||||
@@ -120,6 +120,8 @@ public:
|
||||
void drawRenderNode(RenderNode* node);
|
||||
void setContentDrawBounds(int left, int top, int right, int bottom);
|
||||
void setPictureCapturedCallback(const std::function<void(sk_sp<SkPicture>&&)>& callback);
|
||||
void setASurfaceTransactionCallback(
|
||||
const std::function<void(int64_t, int64_t, int64_t)>& callback);
|
||||
void setFrameCallback(std::function<void(int64_t)>&& callback);
|
||||
void setFrameCompleteCallback(std::function<void(int64_t)>&& callback);
|
||||
|
||||
|
||||
@@ -54,6 +54,10 @@ static JVMAttachHook gOnStartHook = nullptr;
|
||||
|
||||
ASurfaceControlFunctions::ASurfaceControlFunctions() {
|
||||
void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
|
||||
createFunc = (ASC_create)dlsym(handle_, "ASurfaceControl_create");
|
||||
LOG_ALWAYS_FATAL_IF(createFunc == nullptr,
|
||||
"Failed to find required symbol ASurfaceControl_create!");
|
||||
|
||||
acquireFunc = (ASC_acquire) dlsym(handle_, "ASurfaceControl_acquire");
|
||||
LOG_ALWAYS_FATAL_IF(acquireFunc == nullptr,
|
||||
"Failed to find required symbol ASurfaceControl_acquire!");
|
||||
@@ -81,6 +85,23 @@ ASurfaceControlFunctions::ASurfaceControlFunctions() {
|
||||
"ASurfaceControlStats_getFrameNumber");
|
||||
LOG_ALWAYS_FATAL_IF(getFrameNumberFunc == nullptr,
|
||||
"Failed to find required symbol ASurfaceControlStats_getFrameNumber!");
|
||||
|
||||
transactionCreateFunc = (AST_create)dlsym(handle_, "ASurfaceTransaction_create");
|
||||
LOG_ALWAYS_FATAL_IF(transactionCreateFunc == nullptr,
|
||||
"Failed to find required symbol ASurfaceTransaction_create!");
|
||||
|
||||
transactionDeleteFunc = (AST_delete)dlsym(handle_, "ASurfaceTransaction_delete");
|
||||
LOG_ALWAYS_FATAL_IF(transactionDeleteFunc == nullptr,
|
||||
"Failed to find required symbol ASurfaceTransaction_delete!");
|
||||
|
||||
transactionApplyFunc = (AST_apply)dlsym(handle_, "ASurfaceTransaction_apply");
|
||||
LOG_ALWAYS_FATAL_IF(transactionApplyFunc == nullptr,
|
||||
"Failed to find required symbol ASurfaceTransaction_apply!");
|
||||
|
||||
transactionSetVisibilityFunc =
|
||||
(AST_setVisibility)dlsym(handle_, "ASurfaceTransaction_setVisibility");
|
||||
LOG_ALWAYS_FATAL_IF(transactionSetVisibilityFunc == nullptr,
|
||||
"Failed to find required symbol ASurfaceTransaction_setVisibility!");
|
||||
}
|
||||
|
||||
void RenderThread::frameCallback(int64_t frameTimeNanos, void* data) {
|
||||
|
||||
@@ -79,25 +79,39 @@ struct VsyncSource {
|
||||
virtual ~VsyncSource() {}
|
||||
};
|
||||
|
||||
typedef ASurfaceControl* (*ASC_create)(ASurfaceControl* parent, const char* debug_name);
|
||||
typedef void (*ASC_acquire)(ASurfaceControl* control);
|
||||
typedef void (*ASC_release)(ASurfaceControl* control);
|
||||
|
||||
typedef void (*ASC_registerSurfaceStatsListener)(ASurfaceControl* control, void* context,
|
||||
ASurfaceControl_SurfaceStatsListener func);
|
||||
typedef void (*ASC_unregisterSurfaceStatsListener)(void* context,
|
||||
ASurfaceControl_SurfaceStatsListener func);
|
||||
ASurfaceControl_SurfaceStatsListener func);
|
||||
|
||||
typedef int64_t (*ASCStats_getAcquireTime)(ASurfaceControlStats* stats);
|
||||
typedef uint64_t (*ASCStats_getFrameNumber)(ASurfaceControlStats* stats);
|
||||
|
||||
typedef ASurfaceTransaction* (*AST_create)();
|
||||
typedef void (*AST_delete)(ASurfaceTransaction* transaction);
|
||||
typedef void (*AST_apply)(ASurfaceTransaction* transaction);
|
||||
typedef void (*AST_setVisibility)(ASurfaceTransaction* transaction,
|
||||
ASurfaceControl* surface_control, int8_t visibility);
|
||||
|
||||
struct ASurfaceControlFunctions {
|
||||
ASurfaceControlFunctions();
|
||||
|
||||
ASC_create createFunc;
|
||||
ASC_acquire acquireFunc;
|
||||
ASC_release releaseFunc;
|
||||
ASC_registerSurfaceStatsListener registerListenerFunc;
|
||||
ASC_unregisterSurfaceStatsListener unregisterListenerFunc;
|
||||
ASCStats_getAcquireTime getAcquireTimeFunc;
|
||||
ASCStats_getFrameNumber getFrameNumberFunc;
|
||||
|
||||
AST_create transactionCreateFunc;
|
||||
AST_delete transactionDeleteFunc;
|
||||
AST_apply transactionApplyFunc;
|
||||
AST_setVisibility transactionSetVisibilityFunc;
|
||||
};
|
||||
|
||||
class ChoreographerSource;
|
||||
|
||||
Reference in New Issue
Block a user