mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1385003 - Use a different WebRenderAPI instance for each WebRenderBridgeParent. r=kats
Previously, the WebRenderBridgeParent for each content layer tree would use the same WebRenderAPI instance as the top-level WebRenderBridgeParent for that window. However, in order to make the namespacing changes work we now need to use a separate WebRenderAPI instance for each WebRenderBridgeParent. The content WebRenderAPIs are cloned from the parent one, so that they all share the same backend, but can allocate resource IDs in distinct namespaces. MozReview-Commit-ID: 7VTFL8F09n7 --HG-- extra : rebase_source : 2da1d03abc23bd7852e4b12fe133889bd80cad53
This commit is contained in:
parent
8487cf859b
commit
162dcae649
@ -463,6 +463,9 @@ CompositorBridgeParent::StopAndClearResources()
|
||||
});
|
||||
mWrBridge->Destroy();
|
||||
mWrBridge = nullptr;
|
||||
mAsyncImageManager->Destroy();
|
||||
// WebRenderAPI should be already destructed
|
||||
mAsyncImageManager = nullptr;
|
||||
}
|
||||
|
||||
if (mCompositor) {
|
||||
@ -1654,8 +1657,9 @@ CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
|
||||
ScheduleComposition();
|
||||
}
|
||||
if (mWrBridge && sIndirectLayerTrees[child].mWrBridge) {
|
||||
RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI()->Clone();
|
||||
sIndirectLayerTrees[child].mWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(),
|
||||
mWrBridge->GetWebRenderAPI(),
|
||||
api,
|
||||
mWrBridge->AsyncImageManager(),
|
||||
GetAnimationStorage());
|
||||
// Pretend we composited, since parent CompositorBridgeParent was replaced.
|
||||
@ -1702,8 +1706,8 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
|
||||
*aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
|
||||
return mWrBridge;
|
||||
}
|
||||
RefPtr<AsyncImagePipelineManager> asyncMgr =
|
||||
new AsyncImagePipelineManager(api->GetNamespace());
|
||||
mAsyncImageManager = new AsyncImagePipelineManager(api->Clone());
|
||||
RefPtr<AsyncImagePipelineManager> asyncMgr = mAsyncImageManager;
|
||||
api->SetRootPipeline(aPipelineId);
|
||||
RefPtr<CompositorAnimationStorage> animStorage = GetAnimationStorage();
|
||||
mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, Move(api), Move(asyncMgr), Move(animStorage));
|
||||
@ -1953,10 +1957,10 @@ CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
|
||||
void
|
||||
CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
|
||||
{
|
||||
if (!mWrBridge) {
|
||||
if (!mWrBridge || !mAsyncImageManager) {
|
||||
return;
|
||||
}
|
||||
mWrBridge->AsyncImageManager()->Update(aPipelineId, aEpoch);
|
||||
mAsyncImageManager->Update(aPipelineId, aEpoch);
|
||||
|
||||
if (mPaused) {
|
||||
return;
|
||||
|
@ -65,6 +65,7 @@ namespace layers {
|
||||
class APZCTreeManager;
|
||||
class APZCTreeManagerParent;
|
||||
class AsyncCompositionManager;
|
||||
class AsyncImagePipelineManager;
|
||||
class Compositor;
|
||||
class CompositorAnimationStorage;
|
||||
class CompositorBridgeParent;
|
||||
@ -580,6 +581,7 @@ protected:
|
||||
RefPtr<HostLayerManager> mLayerManager;
|
||||
RefPtr<Compositor> mCompositor;
|
||||
RefPtr<AsyncCompositionManager> mCompositionManager;
|
||||
RefPtr<AsyncImagePipelineManager> mAsyncImageManager;
|
||||
RefPtr<WebRenderBridgeParent> mWrBridge;
|
||||
widget::CompositorWidget* mWidget;
|
||||
TimeStamp mTestTime;
|
||||
|
@ -225,7 +225,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
|
||||
}
|
||||
WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWrBridge.get();
|
||||
|
||||
RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI();
|
||||
RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI()->Clone();
|
||||
RefPtr<AsyncImagePipelineManager> holder = root->AsyncImageManager();
|
||||
RefPtr<CompositorAnimationStorage> animStorage = cbp->GetAnimationStorage();
|
||||
parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, root->CompositorScheduler(), Move(api), Move(holder), Move(animStorage));
|
||||
|
@ -23,8 +23,9 @@ AsyncImagePipelineManager::AsyncImagePipeline::AsyncImagePipeline()
|
||||
, mMixBlendMode(wr::MixBlendMode::Normal)
|
||||
{}
|
||||
|
||||
AsyncImagePipelineManager::AsyncImagePipelineManager(wr::IdNamespace aIdNamespace)
|
||||
: mIdNamespace(aIdNamespace)
|
||||
AsyncImagePipelineManager::AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi)
|
||||
: mApi(aApi)
|
||||
, mIdNamespace(mApi->GetNamespace())
|
||||
, mResourceId(0)
|
||||
, mAsyncImageEpoch(0)
|
||||
, mDestroyed(false)
|
||||
@ -38,9 +39,11 @@ AsyncImagePipelineManager::~AsyncImagePipelineManager()
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::Destroy(wr::WebRenderAPI* aApi)
|
||||
AsyncImagePipelineManager::Destroy()
|
||||
{
|
||||
DeleteOldAsyncImages(aApi);
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
DeleteOldAsyncImages();
|
||||
mApi = nullptr;
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
@ -51,10 +54,11 @@ AsyncImagePipelineManager::HasKeysToDelete()
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::DeleteOldAsyncImages(wr::WebRenderAPI* aApi)
|
||||
AsyncImagePipelineManager::DeleteOldAsyncImages()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
for (wr::ImageKey key : mKeysToDelete) {
|
||||
aApi->DeleteImage(key);
|
||||
mApi->DeleteImage(key);
|
||||
}
|
||||
mKeysToDelete.Clear();
|
||||
}
|
||||
@ -111,7 +115,7 @@ AsyncImagePipelineManager::AddAsyncImagePipeline(const wr::PipelineId& aPipeline
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId)
|
||||
AsyncImagePipelineManager::RemoveAsyncImagePipeline(const wr::PipelineId& aPipelineId)
|
||||
{
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
@ -121,9 +125,9 @@ AsyncImagePipelineManager::RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, cons
|
||||
if (auto entry = mAsyncImagePipelines.Lookup(id)) {
|
||||
AsyncImagePipeline* holder = entry.Data();
|
||||
++mAsyncImageEpoch; // Update webrender epoch
|
||||
aApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
|
||||
mApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
|
||||
for (wr::ImageKey key : holder->mKeys) {
|
||||
aApi->DeleteImage(key);
|
||||
mApi->DeleteImage(key);
|
||||
}
|
||||
entry.Remove();
|
||||
RemovePipeline(aPipelineId, wr::NewEpoch(mAsyncImageEpoch));
|
||||
@ -155,7 +159,7 @@ AsyncImagePipelineManager::UpdateAsyncImagePipeline(const wr::PipelineId& aPipel
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncImagePipelineManager::GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys)
|
||||
AsyncImagePipelineManager::GenerateImageKeyForTextureHost(TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys)
|
||||
{
|
||||
MOZ_ASSERT(aKeys.IsEmpty());
|
||||
MOZ_ASSERT(aTexture);
|
||||
@ -166,7 +170,7 @@ AsyncImagePipelineManager::GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi
|
||||
wrTexture->GetWRImageKeys(aKeys, std::bind(&AsyncImagePipelineManager::GenerateImageKey, this));
|
||||
MOZ_ASSERT(!aKeys.IsEmpty());
|
||||
Range<const wr::ImageKey> keys(&aKeys[0], aKeys.Length());
|
||||
wrTexture->AddWRImage(aApi, keys, wrTexture->GetExternalImageKey());
|
||||
wrTexture->AddWRImage(mApi, keys, wrTexture->GetExternalImageKey());
|
||||
return true;
|
||||
} else {
|
||||
RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
|
||||
@ -185,15 +189,14 @@ AsyncImagePipelineManager::GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi
|
||||
|
||||
wr::ImageKey key = GenerateImageKey();
|
||||
aKeys.AppendElement(key);
|
||||
aApi->AddImage(key, descriptor, slice);
|
||||
mApi->AddImage(key, descriptor, slice);
|
||||
dSurf->Unmap();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncImagePipelineManager::UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
bool& aUseExternalImage,
|
||||
AsyncImagePipelineManager::UpdateImageKeys(bool& aUseExternalImage,
|
||||
AsyncImagePipeline* aImageMgr,
|
||||
nsTArray<wr::ImageKey>& aKeys,
|
||||
nsTArray<wr::ImageKey>& aKeysToDelete)
|
||||
@ -231,7 +234,7 @@ AsyncImagePipelineManager::UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
return true;
|
||||
}
|
||||
|
||||
aUseExternalImage = aImageMgr->mUseExternalImage = GenerateImageKeyForTextureHost(aApi, texture, aKeys);
|
||||
aUseExternalImage = aImageMgr->mUseExternalImage = GenerateImageKeyForTextureHost(texture, aKeys);
|
||||
MOZ_ASSERT(!aKeys.IsEmpty());
|
||||
aImageMgr->mKeys.AppendElements(aKeys);
|
||||
aImageMgr->mCurrentTexture = texture;
|
||||
@ -239,7 +242,7 @@ AsyncImagePipelineManager::UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::ApplyAsyncImages(wr::WebRenderAPI* aApi)
|
||||
AsyncImagePipelineManager::ApplyAsyncImages()
|
||||
{
|
||||
if (mDestroyed || mAsyncImagePipelines.Count() == 0) {
|
||||
return;
|
||||
@ -255,8 +258,7 @@ AsyncImagePipelineManager::ApplyAsyncImages(wr::WebRenderAPI* aApi)
|
||||
|
||||
nsTArray<wr::ImageKey> keys;
|
||||
bool useExternalImage = false;
|
||||
bool updateDisplayList = UpdateImageKeys(aApi,
|
||||
useExternalImage,
|
||||
bool updateDisplayList = UpdateImageKeys(useExternalImage,
|
||||
pipeline,
|
||||
keys,
|
||||
keysToDelete);
|
||||
@ -306,11 +308,11 @@ AsyncImagePipelineManager::ApplyAsyncImages(wr::WebRenderAPI* aApi)
|
||||
wr::BuiltDisplayList dl;
|
||||
wr::LayoutSize builderContentSize;
|
||||
builder.Finalize(builderContentSize, dl);
|
||||
aApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.width, pipeline->mScBounds.height),
|
||||
mApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(pipeline->mScBounds.width, pipeline->mScBounds.height),
|
||||
pipelineId, builderContentSize,
|
||||
dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length);
|
||||
}
|
||||
DeleteOldAsyncImages(aApi);
|
||||
DeleteOldAsyncImages();
|
||||
mKeysToDelete.SwapElements(keysToDelete);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/gfx/Point.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
@ -34,13 +35,13 @@ class AsyncImagePipelineManager final
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncImagePipelineManager)
|
||||
|
||||
explicit AsyncImagePipelineManager(wr::IdNamespace aIdNamespace);
|
||||
explicit AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi);
|
||||
|
||||
protected:
|
||||
~AsyncImagePipelineManager();
|
||||
|
||||
public:
|
||||
void Destroy(wr::WebRenderAPI* aApi);
|
||||
void Destroy();
|
||||
bool HasKeysToDelete();
|
||||
|
||||
void AddPipeline(const wr::PipelineId& aPipelineId);
|
||||
@ -70,7 +71,7 @@ public:
|
||||
}
|
||||
|
||||
void AddAsyncImagePipeline(const wr::PipelineId& aPipelineId, WebRenderImageHost* aImageHost);
|
||||
void RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId);
|
||||
void RemoveAsyncImagePipeline(const wr::PipelineId& aPipelineId);
|
||||
|
||||
void UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
|
||||
const LayerRect& aScBounds,
|
||||
@ -78,7 +79,7 @@ public:
|
||||
const gfx::MaybeIntSize& aScaleToSize,
|
||||
const wr::ImageRendering& aFilter,
|
||||
const wr::MixBlendMode& aMixBlendMode);
|
||||
void ApplyAsyncImages(wr::WebRenderAPI* aApi);
|
||||
void ApplyAsyncImages();
|
||||
|
||||
void AppendImageCompositeNotification(const ImageCompositeNotificationInfo& aNotification)
|
||||
{
|
||||
@ -91,7 +92,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void DeleteOldAsyncImages(wr::WebRenderAPI* aApi);
|
||||
void DeleteOldAsyncImages();
|
||||
|
||||
uint32_t GetNextResourceId() { return ++mResourceId; }
|
||||
wr::IdNamespace GetNamespace() { return mIdNamespace; }
|
||||
@ -102,7 +103,7 @@ private:
|
||||
key.mHandle = GetNextResourceId();
|
||||
return key;
|
||||
}
|
||||
bool GenerateImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys);
|
||||
bool GenerateImageKeyForTextureHost(TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys);
|
||||
|
||||
struct ForwardingTextureHost {
|
||||
ForwardingTextureHost(const wr::Epoch& aEpoch, TextureHost* aTexture)
|
||||
@ -135,12 +136,12 @@ private:
|
||||
nsTArray<wr::ImageKey> mKeys;
|
||||
};
|
||||
|
||||
bool UpdateImageKeys(wr::WebRenderAPI* aApi,
|
||||
bool& aUseExternalImage,
|
||||
bool UpdateImageKeys(bool& aUseExternalImage,
|
||||
AsyncImagePipeline* aImageMgr,
|
||||
nsTArray<wr::ImageKey>& aKeys,
|
||||
nsTArray<wr::ImageKey>& aKeysToDelete);
|
||||
|
||||
RefPtr<wr::WebRenderAPI> mApi;
|
||||
wr::IdNamespace mIdNamespace;
|
||||
uint32_t mResourceId;
|
||||
|
||||
|
@ -792,7 +792,7 @@ WebRenderBridgeParent::RecvRemovePipelineIdForCompositable(const wr::PipelineId&
|
||||
}
|
||||
|
||||
wrHost->ClearWrBridge();
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(mApi, aPipelineId);
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(aPipelineId);
|
||||
mAsyncCompositables.Remove(wr::AsUint64(aPipelineId));
|
||||
return IPC_OK();
|
||||
}
|
||||
@ -1116,7 +1116,7 @@ WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::In
|
||||
nsTArray<wr::WrTransformProperty> transformArray;
|
||||
|
||||
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
|
||||
mAsyncImageManager->ApplyAsyncImages(mApi);
|
||||
mAsyncImageManager->ApplyAsyncImages();
|
||||
|
||||
SampleAnimations(opacityArray, transformArray);
|
||||
if (!transformArray.IsEmpty() || !opacityArray.IsEmpty()) {
|
||||
@ -1313,7 +1313,7 @@ WebRenderBridgeParent::ClearResources()
|
||||
wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
|
||||
RefPtr<WebRenderImageHost> host = iter.Data();
|
||||
host->ClearWrBridge();
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(mApi, pipelineId);
|
||||
mAsyncImageManager->RemoveAsyncImagePipeline(pipelineId);
|
||||
}
|
||||
mAsyncCompositables.Clear();
|
||||
|
||||
@ -1329,6 +1329,7 @@ WebRenderBridgeParent::ClearResources()
|
||||
}
|
||||
mAnimStorage = nullptr;
|
||||
mCompositorScheduler = nullptr;
|
||||
mAsyncImageManager = nullptr;
|
||||
mApi = nullptr;
|
||||
mCompositorBridge = nullptr;
|
||||
}
|
||||
@ -1452,6 +1453,9 @@ void
|
||||
WebRenderBridgeParent::ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
|
||||
{
|
||||
MOZ_ASSERT(mWidget);
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
mAsyncImageManager->FlushImageNotifications(aNotifications);
|
||||
}
|
||||
|
||||
|
@ -176,6 +176,17 @@ WebRenderAPI::Create(bool aEnableProfiler,
|
||||
return RefPtr<WebRenderAPI>(new WebRenderAPI(docHandle, id, maxTextureSize, useANGLE, syncHandle)).forget();
|
||||
}
|
||||
|
||||
already_AddRefed<WebRenderAPI>
|
||||
WebRenderAPI::Clone()
|
||||
{
|
||||
wr::DocumentHandle* docHandle = nullptr;
|
||||
wr_api_clone(mDocHandle, &docHandle);
|
||||
|
||||
RefPtr<WebRenderAPI> renderApi = new WebRenderAPI(docHandle, mId, mMaxTextureSize, mUseANGLE, mSyncHandle);
|
||||
renderApi->mRootApi = this; // Hold root api
|
||||
return renderApi.forget();
|
||||
}
|
||||
|
||||
wr::WrIdNamespace
|
||||
WebRenderAPI::GetNamespace() {
|
||||
return wr_api_get_namespace(mDocHandle);
|
||||
@ -183,10 +194,12 @@ WebRenderAPI::GetNamespace() {
|
||||
|
||||
WebRenderAPI::~WebRenderAPI()
|
||||
{
|
||||
layers::SynchronousTask task("Destroy WebRenderAPI");
|
||||
auto event = MakeUnique<RemoveRenderer>(&task);
|
||||
RunOnRenderThread(Move(event));
|
||||
task.Wait();
|
||||
if (!mRootApi) {
|
||||
layers::SynchronousTask task("Destroy WebRenderAPI");
|
||||
auto event = MakeUnique<RemoveRenderer>(&task);
|
||||
RunOnRenderThread(Move(event));
|
||||
task.Wait();
|
||||
}
|
||||
|
||||
wr_api_delete(mDocHandle);
|
||||
}
|
||||
|
@ -47,6 +47,8 @@ public:
|
||||
RefPtr<widget::CompositorWidget>&& aWidget,
|
||||
LayoutDeviceIntSize aSize);
|
||||
|
||||
already_AddRefed<WebRenderAPI> Clone();
|
||||
|
||||
wr::WindowId GetId() const { return mId; }
|
||||
|
||||
void UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
|
||||
@ -143,6 +145,7 @@ protected:
|
||||
GLint mMaxTextureSize;
|
||||
bool mUseANGLE;
|
||||
layers::SyncHandle mSyncHandle;
|
||||
RefPtr<wr::WebRenderAPI> mRootApi;
|
||||
|
||||
friend class DisplayListBuilder;
|
||||
friend class layers::WebRenderBridgeParent;
|
||||
|
@ -610,12 +610,26 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
|
||||
return true;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_api_clone(dh: &mut DocumentHandle,
|
||||
out_handle: &mut *mut DocumentHandle) {
|
||||
assert!(unsafe { is_in_compositor_thread() });
|
||||
|
||||
let handle = DocumentHandle {
|
||||
api: dh.api.clone_sender().create_api(),
|
||||
document_id: dh.document_id,
|
||||
};
|
||||
*out_handle = Box::into_raw(Box::new(handle));
|
||||
}
|
||||
|
||||
/// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_api_delete(dh: *mut DocumentHandle) {
|
||||
let handle = Box::from_raw(dh);
|
||||
handle.api.delete_document(handle.document_id);
|
||||
handle.api.shut_down();
|
||||
if handle.document_id.0 == handle.api.get_namespace_id() {
|
||||
handle.api.delete_document(handle.document_id);
|
||||
handle.api.shut_down();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -860,7 +874,7 @@ pub extern "C" fn wr_api_delete_font(dh: &mut DocumentHandle,
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNamespace {
|
||||
dh.document_id.0
|
||||
dh.api.get_namespace_id()
|
||||
}
|
||||
|
||||
// RenderThread WIP notes:
|
||||
|
Loading…
Reference in New Issue
Block a user