Bug 825928: Land layers refactoring. r=jrmuizel,bas,nical,mattwoodrow,roc,nrc,benwa,bjacob,jgilbert,kchen CLOSED TREE
Please contact Bas Schouten <bschouten@mozilla.com>, Nicolas Silva <nsilva@mozilla.com> or Nicholas Cameron <ncameron@mozilla.com> with general questions. Below is a rough list of authors to contact with specific questions.
Authors:
gfx/layers/Compositor.* gfx/layers/Effects.h - Compositor Interface - bas,nrc,nical
gfx/layers/d3d* - D3D9/D3D10 - bas
gfx/layers/ThebesLayer* - ThebesLayers - nrc,bas
gfx/layers/composite/* - CompositeLayers - nrc,nical
gfx/layers/client/* - Client - nrc,nical,bas
gfx/layers/*Image* - nical
gfx/layers/ipc ipc - IPC - nical
gfx/layers/opengl - CompositorOGL - nrc,nical
gfx/2d - bas,nrc
gfx/gl - GLContext - bjacob
dom/* layout/* - DOM - mattwoodrow
2013-04-10 13:20:52 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "mozilla/layers/TextureClient.h"
|
2013-08-12 03:17:23 +04:00
|
|
|
#include <stdint.h> // for uint8_t, uint32_t, etc
|
|
|
|
#include "Layers.h" // for Layer, etc
|
2013-12-20 20:46:29 +04:00
|
|
|
#include "gfx2DGlue.h"
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "gfxPlatform.h" // for gfxPlatform
|
2015-10-16 15:46:33 +03:00
|
|
|
#include "mozilla/Atomics.h"
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
|
2015-12-02 22:31:17 +03:00
|
|
|
#include "mozilla/layers/AsyncTransactionTracker.h"
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "mozilla/layers/CompositableForwarder.h"
|
|
|
|
#include "mozilla/layers/ISurfaceAllocator.h"
|
|
|
|
#include "mozilla/layers/ImageDataSerializer.h"
|
2015-12-02 22:31:17 +03:00
|
|
|
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
2013-08-12 03:17:23 +04:00
|
|
|
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
|
2014-02-27 01:36:35 +04:00
|
|
|
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
2014-07-15 11:59:34 +04:00
|
|
|
#include "ImageContainer.h" // for PlanarYCbCrData, etc
|
2013-10-16 05:00:30 +04:00
|
|
|
#include "mozilla/gfx/2D.h"
|
2014-12-09 21:19:29 +03:00
|
|
|
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
2014-03-08 01:34:04 +04:00
|
|
|
#include "mozilla/layers/TextureClientOGL.h"
|
2014-04-28 15:29:13 +04:00
|
|
|
#include "mozilla/layers/PTextureChild.h"
|
2014-12-18 21:32:45 +03:00
|
|
|
#include "mozilla/gfx/DataSurfaceHelpers.h" // for CreateDataSourceSurfaceByCloning
|
|
|
|
#include "nsPrintfCString.h" // for nsPrintfCString
|
|
|
|
#include "LayersLogging.h" // for AppendToString
|
|
|
|
#include "gfxUtils.h" // for gfxUtils::GetAsLZ4Base64Str
|
2015-11-06 18:56:03 +03:00
|
|
|
#include "IPDLActor.h"
|
2015-10-15 18:53:33 +03:00
|
|
|
#include "BufferTexture.h"
|
2015-12-02 22:31:17 +03:00
|
|
|
#include "gfxPrefs.h"
|
2014-03-08 01:34:04 +04:00
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
#include "mozilla/layers/TextureD3D9.h"
|
|
|
|
#include "mozilla/layers/TextureD3D11.h"
|
2014-07-11 01:29:40 +04:00
|
|
|
#include "mozilla/layers/TextureDIB.h"
|
2014-03-08 01:34:04 +04:00
|
|
|
#include "gfxWindowsPlatform.h"
|
|
|
|
#include "gfx2DGlue.h"
|
|
|
|
#endif
|
|
|
|
#ifdef MOZ_X11
|
|
|
|
#include "mozilla/layers/TextureClientX11.h"
|
|
|
|
#ifdef GL_PROVIDER_GLX
|
|
|
|
#include "GLXLibrary.h"
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MOZ_WIDGET_GONK
|
|
|
|
#include <cutils/properties.h>
|
|
|
|
#include "mozilla/layers/GrallocTextureClient.h"
|
|
|
|
#endif
|
2013-08-12 06:21:17 +04:00
|
|
|
|
2014-08-22 23:26:56 +04:00
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
2013-08-19 17:59:27 +04:00
|
|
|
# include "gfxReusableImageSurfaceWrapper.h"
|
|
|
|
#else
|
|
|
|
# include "gfxReusableSharedImageSurfaceWrapper.h"
|
|
|
|
# include "gfxSharedImageSurface.h"
|
|
|
|
#endif
|
|
|
|
|
2014-03-10 22:34:57 +04:00
|
|
|
#if 0
|
|
|
|
#define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define RECYCLE_LOG(...) do { } while (0)
|
|
|
|
#endif
|
|
|
|
|
Bug 825928: Land layers refactoring. r=jrmuizel,bas,nical,mattwoodrow,roc,nrc,benwa,bjacob,jgilbert,kchen CLOSED TREE
Please contact Bas Schouten <bschouten@mozilla.com>, Nicolas Silva <nsilva@mozilla.com> or Nicholas Cameron <ncameron@mozilla.com> with general questions. Below is a rough list of authors to contact with specific questions.
Authors:
gfx/layers/Compositor.* gfx/layers/Effects.h - Compositor Interface - bas,nrc,nical
gfx/layers/d3d* - D3D9/D3D10 - bas
gfx/layers/ThebesLayer* - ThebesLayers - nrc,bas
gfx/layers/composite/* - CompositeLayers - nrc,nical
gfx/layers/client/* - Client - nrc,nical,bas
gfx/layers/*Image* - nical
gfx/layers/ipc ipc - IPC - nical
gfx/layers/opengl - CompositorOGL - nrc,nical
gfx/2d - bas,nrc
gfx/gl - GLContext - bjacob
dom/* layout/* - DOM - mattwoodrow
2013-04-10 13:20:52 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace layers {
|
|
|
|
|
2014-05-22 14:11:45 +04:00
|
|
|
using namespace mozilla::ipc;
|
|
|
|
using namespace mozilla::gl;
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
struct TextureDeallocParams
|
|
|
|
{
|
|
|
|
TextureData* data;
|
|
|
|
RefPtr<TextureChild> actor;
|
|
|
|
RefPtr<ISurfaceAllocator> allocator;
|
|
|
|
bool clientDeallocation;
|
|
|
|
bool syncDeallocation;
|
|
|
|
bool workAroundSharedSurfaceOwnershipIssue;
|
2015-11-24 21:07:02 +03:00
|
|
|
};
|
2015-11-20 16:25:03 +03:00
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
void DeallocateTextureClient(TextureDeallocParams params);
|
|
|
|
|
2013-12-12 05:44:45 +04:00
|
|
|
/**
|
|
|
|
* TextureChild is the content-side incarnation of the PTexture IPDL actor.
|
|
|
|
*
|
|
|
|
* TextureChild is used to synchronize a texture client and its corresponding
|
|
|
|
* TextureHost if needed (a TextureClient that is not shared with the compositor
|
|
|
|
* does not have a TextureChild)
|
|
|
|
*
|
|
|
|
* During the deallocation phase, a TextureChild may hold its recently destroyed
|
|
|
|
* TextureClient's data until the compositor side confirmed that it is safe to
|
|
|
|
* deallocte or recycle the it.
|
|
|
|
*/
|
2015-11-06 18:56:03 +03:00
|
|
|
class TextureChild final : public ChildActor<PTextureChild>
|
2013-12-12 05:44:44 +04:00
|
|
|
{
|
2015-03-26 03:05:25 +03:00
|
|
|
~TextureChild()
|
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
// We should have deallocated mTextureData in ActorDestroy
|
|
|
|
MOZ_ASSERT(!mTextureData);
|
2015-03-26 03:05:25 +03:00
|
|
|
}
|
2013-12-12 05:44:44 +04:00
|
|
|
public:
|
2014-04-14 23:04:25 +04:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild)
|
|
|
|
|
2013-12-12 05:44:45 +04:00
|
|
|
TextureChild()
|
|
|
|
: mForwarder(nullptr)
|
2015-10-16 15:46:33 +03:00
|
|
|
, mMonitor("TextureChild")
|
|
|
|
, mTextureClient(nullptr)
|
2015-11-20 16:25:03 +03:00
|
|
|
, mTextureData(nullptr)
|
2015-10-16 15:46:33 +03:00
|
|
|
, mDestroyed(false)
|
2015-10-16 16:22:06 +03:00
|
|
|
, mMainThreadOnly(false)
|
|
|
|
, mIPCOpen(false)
|
2015-11-20 16:25:03 +03:00
|
|
|
, mOwnsTextureData(false)
|
|
|
|
{}
|
2013-12-12 05:44:45 +04:00
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
bool Recv__delete__() override { return true; }
|
2013-12-12 05:44:45 +04:00
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
bool RecvCompositorRecycle() override
|
2014-03-10 22:34:57 +04:00
|
|
|
{
|
2015-06-05 03:15:38 +03:00
|
|
|
RECYCLE_LOG("[CLIENT] Receive recycle %p (%p)\n", mTextureClient, mWaitForRecycle.get());
|
2014-03-10 22:34:57 +04:00
|
|
|
mWaitForRecycle = nullptr;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WaitForCompositorRecycle()
|
|
|
|
{
|
2015-10-16 15:46:33 +03:00
|
|
|
{
|
|
|
|
MonitorAutoLock mon(mMonitor);
|
|
|
|
mWaitForRecycle = mDestroyed ? nullptr : mTextureClient;
|
|
|
|
}
|
2015-06-05 03:15:38 +03:00
|
|
|
RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get());
|
2015-11-06 18:56:03 +03:00
|
|
|
MOZ_ASSERT(CanSend());
|
2014-03-10 22:34:57 +04:00
|
|
|
SendClientRecycle();
|
|
|
|
}
|
|
|
|
|
2013-12-12 05:44:45 +04:00
|
|
|
CompositableForwarder* GetForwarder() { return mForwarder; }
|
|
|
|
|
|
|
|
ISurfaceAllocator* GetAllocator() { return mForwarder; }
|
|
|
|
|
2015-03-21 19:28:04 +03:00
|
|
|
void ActorDestroy(ActorDestroyReason why) override;
|
2013-12-12 05:44:55 +04:00
|
|
|
|
2013-12-21 01:44:30 +04:00
|
|
|
bool IPCOpen() const { return mIPCOpen; }
|
|
|
|
|
2013-12-12 05:44:55 +04:00
|
|
|
private:
|
|
|
|
|
2013-12-21 01:44:30 +04:00
|
|
|
// AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
|
|
|
|
// and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
|
|
|
|
// The purpose of these methods is to be aware of when the IPC system around this
|
|
|
|
// actor goes down: mIPCOpen is then set to false.
|
|
|
|
void AddIPDLReference() {
|
|
|
|
MOZ_ASSERT(mIPCOpen == false);
|
|
|
|
mIPCOpen = true;
|
|
|
|
AddRef();
|
|
|
|
}
|
|
|
|
void ReleaseIPDLReference() {
|
|
|
|
MOZ_ASSERT(mIPCOpen == true);
|
|
|
|
mIPCOpen = false;
|
|
|
|
Release();
|
|
|
|
}
|
|
|
|
|
2015-10-16 15:46:33 +03:00
|
|
|
void SetTextureClient(TextureClient* aTextureClient) {
|
|
|
|
MonitorAutoLock mon(mMonitor);
|
|
|
|
mTextureClient = aTextureClient;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<CompositableForwarder> mForwarder;
|
|
|
|
RefPtr<TextureClient> mWaitForRecycle;
|
2015-10-16 15:46:33 +03:00
|
|
|
|
|
|
|
// Monitor protecting mTextureClient.
|
|
|
|
Monitor mMonitor;
|
2013-12-12 05:44:55 +04:00
|
|
|
TextureClient* mTextureClient;
|
2015-11-20 16:25:03 +03:00
|
|
|
TextureData* mTextureData;
|
2015-10-16 15:46:33 +03:00
|
|
|
Atomic<bool> mDestroyed;
|
2015-03-26 03:05:25 +03:00
|
|
|
bool mMainThreadOnly;
|
2013-12-21 01:44:30 +04:00
|
|
|
bool mIPCOpen;
|
2015-11-20 16:25:03 +03:00
|
|
|
bool mOwnsTextureData;
|
2013-12-12 05:44:44 +04:00
|
|
|
|
2013-12-12 05:44:55 +04:00
|
|
|
friend class TextureClient;
|
2015-11-20 16:25:03 +03:00
|
|
|
friend void DeallocateTextureClient(TextureDeallocParams params);
|
2013-12-12 05:44:44 +04:00
|
|
|
};
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
|
|
|
|
static void DestroyTextureData(TextureData* aTextureData, ISurfaceAllocator* aAllocator,
|
|
|
|
bool aDeallocate, bool aMainThreadOnly)
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
if (!aTextureData) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aMainThreadOnly && !NS_IsMainThread()) {
|
|
|
|
RefPtr<ISurfaceAllocator> allocatorRef = aAllocator;
|
|
|
|
NS_DispatchToMainThread(NS_NewRunnableFunction([aTextureData, allocatorRef, aDeallocate]() -> void {
|
|
|
|
DestroyTextureData(aTextureData, allocatorRef, aDeallocate, true);
|
|
|
|
}));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aDeallocate) {
|
|
|
|
aTextureData->Deallocate(aAllocator);
|
|
|
|
} else {
|
|
|
|
aTextureData->Forget(aAllocator);
|
|
|
|
}
|
|
|
|
delete aTextureData;
|
2015-10-13 19:48:48 +03:00
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
void
|
2015-11-24 21:07:02 +03:00
|
|
|
TextureChild::ActorDestroy(ActorDestroyReason why)
|
2015-10-15 18:53:37 +03:00
|
|
|
{
|
2016-01-15 01:03:11 +03:00
|
|
|
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS);
|
2015-11-24 21:07:02 +03:00
|
|
|
mWaitForRecycle = nullptr;
|
2015-11-20 16:25:03 +03:00
|
|
|
|
|
|
|
if (mTextureData) {
|
|
|
|
DestroyTextureData(mTextureData, GetAllocator(), mOwnsTextureData, mMainThreadOnly);
|
|
|
|
mTextureData = nullptr;
|
|
|
|
}
|
2015-10-15 18:53:37 +03:00
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
void DeallocateTextureClientSyncProxy(TextureDeallocParams params,
|
|
|
|
ReentrantMonitor* aBarrier, bool* aDone)
|
|
|
|
{
|
|
|
|
DeallocateTextureClient(params);
|
|
|
|
ReentrantMonitorAutoEnter autoMon(*aBarrier);
|
|
|
|
*aDone = true;
|
|
|
|
aBarrier->NotifyAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The logic for synchronizing a TextureClient's deallocation goes here.
|
|
|
|
///
|
|
|
|
/// This funciton takes care of dispatching work to the right thread using
|
|
|
|
/// a synchronous proxy if needed, and handles client/host deallocation.
|
|
|
|
void
|
|
|
|
DeallocateTextureClient(TextureDeallocParams params)
|
|
|
|
{
|
2016-01-12 18:00:24 +03:00
|
|
|
if (!params.actor && !params.data) {
|
|
|
|
// Nothing to do
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
TextureChild* actor = params.actor;
|
|
|
|
MessageLoop* ipdlMsgLoop = nullptr;
|
|
|
|
|
|
|
|
if (params.allocator) {
|
|
|
|
ipdlMsgLoop = params.allocator->GetMessageLoop();
|
|
|
|
if (!ipdlMsgLoop) {
|
|
|
|
// An allocator with no message loop means we are too late in the shutdown
|
|
|
|
// sequence.
|
|
|
|
gfxCriticalError() << "Texture deallocated too late during shutdown";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// First make sure that the work is happening on the IPDL thread.
|
|
|
|
if (ipdlMsgLoop && MessageLoop::current() != ipdlMsgLoop) {
|
|
|
|
if (params.syncDeallocation) {
|
|
|
|
bool done = false;
|
|
|
|
ReentrantMonitor barrier("DeallocateTextureClient");
|
|
|
|
ReentrantMonitorAutoEnter autoMon(barrier);
|
|
|
|
ipdlMsgLoop->PostTask(FROM_HERE,
|
|
|
|
NewRunnableFunction(DeallocateTextureClientSyncProxy,
|
|
|
|
params, &barrier, &done));
|
|
|
|
while (!done) {
|
|
|
|
barrier.Wait();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ipdlMsgLoop->PostTask(FROM_HERE,
|
|
|
|
NewRunnableFunction(DeallocateTextureClient, params));
|
|
|
|
}
|
|
|
|
// The work has been forwarded to the IPDL thread, we are done.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Below this line, we are either in the IPDL thread or ther is no IPDL
|
|
|
|
// thread anymore.
|
|
|
|
|
|
|
|
if (!ipdlMsgLoop) {
|
|
|
|
// If we don't have a message loop we can't know for sure that we are in
|
|
|
|
// the IPDL thread and use the ISurfaceAllocator.
|
|
|
|
// This should ideally not happen outside of gtest, but some shutdown raciness
|
|
|
|
// could put us in this situation.
|
|
|
|
params.allocator = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!actor) {
|
|
|
|
// We don't have an IPDL actor, probably because we destroyed the TextureClient
|
|
|
|
// before sharing it with the compositor. It means the data cannot be owned by
|
|
|
|
// the TextureHost since we never created the TextureHost...
|
|
|
|
// ..except if the lovely mWorkaroundAnnoyingSharedSurfaceOwnershipIssues member
|
|
|
|
// is set to true. In this case we are in a special situation where this
|
|
|
|
// TextureClient is in wrapped into another TextureClient which assumes it owns
|
|
|
|
// our data. This is specific to the gralloc SharedSurface.
|
|
|
|
bool shouldDeallocate = !params.workAroundSharedSurfaceOwnershipIssue;
|
|
|
|
DestroyTextureData(params.data, params.allocator,
|
|
|
|
shouldDeallocate,
|
|
|
|
false); // main-thread deallocation
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!actor->IPCOpen()) {
|
|
|
|
// The actor is already deallocated which probably means there was a shutdown
|
|
|
|
// race causing this function to be called concurrently which is bad!
|
|
|
|
gfxCriticalError() << "Racy texture deallocation";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params.syncDeallocation) {
|
|
|
|
MOZ_PERFORMANCE_WARNING("gfx",
|
|
|
|
"TextureClient/Host pair requires synchronous deallocation");
|
2016-01-07 13:17:40 +03:00
|
|
|
actor->DestroySynchronously(actor->GetForwarder());
|
2015-11-20 16:25:03 +03:00
|
|
|
DestroyTextureData(params.data, params.allocator, params.clientDeallocation,
|
|
|
|
actor->mMainThreadOnly);
|
|
|
|
} else {
|
|
|
|
actor->mTextureData = params.data;
|
|
|
|
actor->mOwnsTextureData = params.clientDeallocation;
|
2016-01-07 13:17:40 +03:00
|
|
|
actor->Destroy(actor->GetForwarder());
|
2015-11-20 16:25:03 +03:00
|
|
|
// DestroyTextureData will be called by TextureChild::ActorDestroy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextureClient::Destroy(bool aForceSync)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!IsLocked());
|
|
|
|
|
|
|
|
RefPtr<TextureChild> actor = mActor;
|
|
|
|
mActor = nullptr;
|
|
|
|
|
|
|
|
if (actor && !actor->mDestroyed.compareExchange(false, true)) {
|
|
|
|
actor = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureData* data = mData;
|
|
|
|
if (!mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
|
|
|
|
mData = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data || actor) {
|
|
|
|
TextureDeallocParams params;
|
|
|
|
params.actor = actor;
|
|
|
|
params.allocator = mAllocator;
|
|
|
|
params.clientDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
|
|
|
|
params.workAroundSharedSurfaceOwnershipIssue = mWorkaroundAnnoyingSharedSurfaceOwnershipIssues;
|
|
|
|
if (mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
|
|
|
|
params.data = nullptr;
|
|
|
|
} else {
|
|
|
|
params.data = data;
|
|
|
|
}
|
|
|
|
// At the moment we always deallocate synchronously when deallocating on the
|
|
|
|
// client side, but having asynchronous deallocate in some of the cases will
|
|
|
|
// be a worthwhile optimization.
|
|
|
|
params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT) || aForceSync;
|
|
|
|
DeallocateTextureClient(params);
|
|
|
|
}
|
|
|
|
}
|
2015-10-15 18:53:33 +03:00
|
|
|
|
2016-01-07 13:17:40 +03:00
|
|
|
bool
|
|
|
|
TextureClient::DestroyFallback(PTextureChild* aActor)
|
|
|
|
{
|
|
|
|
// should not end up here so crash debug builds.
|
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return aActor->SendDestroySync();
|
|
|
|
}
|
|
|
|
|
2015-10-13 19:48:48 +03:00
|
|
|
bool
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::Lock(OpenMode aMode)
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
MOZ_ASSERT(!mIsLocked);
|
|
|
|
if (mIsLocked) {
|
|
|
|
return mOpenMode == aMode;
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
if (mRemoveFromCompositableWaiter) {
|
|
|
|
mRemoveFromCompositableWaiter->WaitComplete();
|
|
|
|
mRemoveFromCompositableWaiter = nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
mIsLocked = mData->Lock(aMode, mReleaseFenceHandle.IsValid() ? &mReleaseFenceHandle : nullptr);
|
2015-10-13 19:48:48 +03:00
|
|
|
mOpenMode = aMode;
|
|
|
|
|
2015-12-30 15:23:01 +03:00
|
|
|
auto format = GetFormat();
|
|
|
|
if (mIsLocked && CanExposeDrawTarget() &&
|
|
|
|
aMode == OpenMode::OPEN_READ_WRITE &&
|
|
|
|
NS_IsMainThread() &&
|
|
|
|
// the formats that we apparently expect, in the cairo backend. Any other
|
|
|
|
// format will trigger an assertion in GfxFormatToCairoFormat.
|
|
|
|
(format == SurfaceFormat::A8R8G8B8_UINT32 ||
|
|
|
|
format == SurfaceFormat::X8R8G8B8_UINT32 ||
|
|
|
|
format == SurfaceFormat::A8 ||
|
|
|
|
format == SurfaceFormat::R5G6B5_UINT16)) {
|
|
|
|
if (!BorrowDrawTarget()) {
|
|
|
|
// Failed to get a DrawTarget, means we won't be able to write into the
|
|
|
|
// texture, might as well fail now.
|
|
|
|
Unlock();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-13 19:48:48 +03:00
|
|
|
return mIsLocked;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::Unlock()
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
MOZ_ASSERT(mIsLocked);
|
|
|
|
if (!mIsLocked) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mBorrowedDrawTarget) {
|
2015-10-15 18:53:33 +03:00
|
|
|
MOZ_ASSERT(mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
|
2015-10-13 19:48:48 +03:00
|
|
|
if (mOpenMode & OpenMode::OPEN_WRITE) {
|
|
|
|
mBorrowedDrawTarget->Flush();
|
2015-10-15 18:53:37 +03:00
|
|
|
if (mReadbackSink && !mData->ReadBack(mReadbackSink)) {
|
|
|
|
// Fallback implementation for reading back, because mData does not
|
|
|
|
// have a backend-specific implementation and returned false.
|
2015-10-13 19:48:48 +03:00
|
|
|
RefPtr<SourceSurface> snapshot = mBorrowedDrawTarget->Snapshot();
|
|
|
|
RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
|
|
|
|
mReadbackSink->ProcessReadback(dataSurf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mBorrowedDrawTarget = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mData->Unlock();
|
|
|
|
mIsLocked = false;
|
|
|
|
mOpenMode = OpenMode::OPEN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::HasInternalBuffer() const
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
return mData->HasInternalBuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::IntSize
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::GetSize() const
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
return mData->GetSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx::SurfaceFormat
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::GetFormat() const
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
return mData->GetFormat();
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::~TextureClient()
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
Destroy(false);
|
2015-10-15 18:53:37 +03:00
|
|
|
}
|
|
|
|
|
2015-10-13 19:48:48 +03:00
|
|
|
void
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
MOZ_ASSERT(mIsLocked);
|
2015-10-15 18:53:33 +03:00
|
|
|
MOZ_ASSERT(aSurface);
|
2015-12-30 15:23:01 +03:00
|
|
|
// If you run into this assertion, make sure the texture was locked write-only
|
|
|
|
// rather than read-write.
|
|
|
|
MOZ_ASSERT(!mBorrowedDrawTarget);
|
2015-10-15 18:53:33 +03:00
|
|
|
|
|
|
|
// XXX - It would be better to first try the DrawTarget approach and fallback
|
|
|
|
// to the backend-specific implementation because the latter will usually do
|
|
|
|
// an expensive read-back + cpu-side copy if the texture is on the gpu.
|
|
|
|
// There is a bug with the DrawTarget approach, though specific to reading back
|
|
|
|
// from WebGL (where R and B channel end up inverted) to figure out first.
|
|
|
|
if (mData->UpdateFromSurface(aSurface)) {
|
|
|
|
return;
|
|
|
|
}
|
2015-10-13 19:48:48 +03:00
|
|
|
if (CanExposeDrawTarget() && NS_IsMainThread()) {
|
|
|
|
RefPtr<DrawTarget> dt = BorrowDrawTarget();
|
|
|
|
|
|
|
|
MOZ_ASSERT(dt);
|
2015-10-15 18:53:33 +03:00
|
|
|
if (dt) {
|
|
|
|
dt->CopySurface(aSurface,
|
|
|
|
gfx::IntRect(gfx::IntPoint(0, 0), aSurface->GetSize()),
|
|
|
|
gfx::IntPoint(0, 0));
|
2015-10-13 19:48:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-11-20 16:25:00 +03:00
|
|
|
NS_WARNING("TextureClient::UpdateFromSurface failed");
|
2015-10-13 19:48:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
already_AddRefed<TextureClient>
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
TextureData* data = mData->CreateSimilar(mAllocator, aFlags, aAllocFlags);
|
|
|
|
if (!data) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:00 +03:00
|
|
|
return MakeAndAddRef<TextureClient>(data, aFlags, mAllocator);
|
2015-10-13 19:48:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gfx::DrawTarget*
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::BorrowDrawTarget()
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
MOZ_ASSERT(mIsLocked);
|
|
|
|
// TODO- We can't really assert that at the moment because there is code that Borrows
|
|
|
|
// the DrawTarget, just to get a snapshot, which is legit in term of OpenMode
|
|
|
|
// but we should have a way to get a SourceSurface directly instead.
|
|
|
|
//MOZ_ASSERT(mOpenMode & OpenMode::OPEN_WRITE);
|
|
|
|
|
|
|
|
if (!mIsLocked) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-13 19:48:48 +03:00
|
|
|
if (!mBorrowedDrawTarget) {
|
|
|
|
mBorrowedDrawTarget = mData->BorrowDrawTarget();
|
2015-10-15 18:53:33 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
mExpectedDtRefs = mBorrowedDrawTarget ? mBorrowedDrawTarget->refCount() : 0;
|
|
|
|
#endif
|
2015-10-13 19:48:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return mBorrowedDrawTarget;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:33 +03:00
|
|
|
bool
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::BorrowMappedData(MappedTextureData& aMap)
|
2015-10-15 18:53:33 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-15 18:53:33 +03:00
|
|
|
|
|
|
|
// TODO - SharedRGBImage just accesses the buffer without properly locking
|
|
|
|
// the texture. It's bad.
|
|
|
|
//MOZ_ASSERT(mIsLocked);
|
|
|
|
//if (!mIsLocked) {
|
|
|
|
// return nullptr;
|
|
|
|
//}
|
|
|
|
|
|
|
|
return mData->BorrowMappedData(aMap);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
|
2015-10-15 18:53:33 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-15 18:53:33 +03:00
|
|
|
return mData->BorrowMappedYCbCrData(aMap);
|
|
|
|
}
|
|
|
|
|
2015-10-13 19:48:48 +03:00
|
|
|
bool
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
2015-10-13 19:48:48 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
MOZ_ASSERT(IsValid());
|
2015-10-13 19:48:48 +03:00
|
|
|
return mData->Serialize(aOutDescriptor);
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
void
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::WaitForBufferOwnership(bool aWaitReleaseFence)
|
2015-10-15 18:53:37 +03:00
|
|
|
{
|
|
|
|
if (mRemoveFromCompositableWaiter) {
|
|
|
|
mRemoveFromCompositableWaiter->WaitComplete();
|
|
|
|
mRemoveFromCompositableWaiter = nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 21
|
2015-10-15 18:53:37 +03:00
|
|
|
if (aWaitReleaseFence && mReleaseFenceHandle.IsValid()) {
|
|
|
|
mData->WaitForFence(&mReleaseFenceHandle);
|
|
|
|
mReleaseFenceHandle = FenceHandle();
|
|
|
|
}
|
2015-11-20 16:25:03 +03:00
|
|
|
#endif
|
2015-10-15 18:53:37 +03:00
|
|
|
}
|
|
|
|
|
2013-12-12 05:44:44 +04:00
|
|
|
// static
|
|
|
|
PTextureChild*
|
|
|
|
TextureClient::CreateIPDLActor()
|
|
|
|
{
|
2013-12-21 01:44:30 +04:00
|
|
|
TextureChild* c = new TextureChild();
|
|
|
|
c->AddIPDLReference();
|
|
|
|
return c;
|
2013-12-12 05:44:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool
|
|
|
|
TextureClient::DestroyIPDLActor(PTextureChild* actor)
|
|
|
|
{
|
2013-12-21 01:44:30 +04:00
|
|
|
static_cast<TextureChild*>(actor)->ReleaseIPDLReference();
|
2013-12-12 05:44:44 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-02-25 08:23:41 +04:00
|
|
|
// static
|
|
|
|
TextureClient*
|
|
|
|
TextureClient::AsTextureClient(PTextureChild* actor)
|
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
if (!actor) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
TextureChild* tc = static_cast<TextureChild*>(actor);
|
|
|
|
if (tc->mDestroyed) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tc->mTextureClient;
|
2014-03-10 22:34:57 +04:00
|
|
|
}
|
|
|
|
|
2015-09-30 19:17:30 +03:00
|
|
|
bool
|
|
|
|
TextureClient::IsSharedWithCompositor() const {
|
2015-11-20 16:25:03 +03:00
|
|
|
return mActor && mActor->IPCOpen();
|
2015-09-30 19:17:30 +03:00
|
|
|
}
|
|
|
|
|
2014-11-13 18:53:49 +03:00
|
|
|
void
|
|
|
|
TextureClient::AddFlags(TextureFlags aFlags)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!IsSharedWithCompositor() ||
|
|
|
|
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
|
|
|
|
mFlags |= aFlags;
|
2015-11-20 16:25:03 +03:00
|
|
|
if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
|
2014-11-13 18:53:49 +03:00
|
|
|
mActor->SendRecycleTexture(mFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TextureClient::RemoveFlags(TextureFlags aFlags)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!IsSharedWithCompositor() ||
|
|
|
|
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
|
|
|
|
mFlags &= ~aFlags;
|
2015-11-20 16:25:03 +03:00
|
|
|
if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
|
2014-11-13 18:53:49 +03:00
|
|
|
mActor->SendRecycleTexture(mFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TextureClient::RecycleTexture(TextureFlags aFlags)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
|
|
|
|
|
|
|
|
mAddedToCompositableClient = false;
|
|
|
|
if (mFlags != aFlags) {
|
|
|
|
mFlags = aFlags;
|
2015-11-20 16:25:03 +03:00
|
|
|
if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
|
2014-11-13 18:53:49 +03:00
|
|
|
mActor->SendRecycleTexture(mFlags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-10 22:34:57 +04:00
|
|
|
void
|
|
|
|
TextureClient::WaitForCompositorRecycle()
|
|
|
|
{
|
2016-01-26 23:46:18 +03:00
|
|
|
if (IsSharedWithCompositor()) {
|
|
|
|
mActor->WaitForCompositorRecycle();
|
|
|
|
}
|
2014-02-25 08:23:41 +04:00
|
|
|
}
|
|
|
|
|
2014-11-13 18:53:49 +03:00
|
|
|
void
|
|
|
|
TextureClient::SetAddedToCompositableClient()
|
|
|
|
{
|
|
|
|
if (!mAddedToCompositableClient) {
|
|
|
|
mAddedToCompositableClient = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-13 22:18:53 +03:00
|
|
|
/* static */ void
|
|
|
|
TextureClient::TextureClientRecycleCallback(TextureClient* aClient, void* aClosure)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aClient->GetRecycleAllocator());
|
|
|
|
aClient->GetRecycleAllocator()->RecycleTextureClient(aClient);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-01-08 14:24:00 +03:00
|
|
|
TextureClient::SetRecycleAllocator(ITextureClientRecycleAllocator* aAllocator)
|
2015-08-13 22:18:53 +03:00
|
|
|
{
|
|
|
|
mRecycleAllocator = aAllocator;
|
|
|
|
if (aAllocator) {
|
|
|
|
SetRecycleCallback(TextureClientRecycleCallback, nullptr);
|
|
|
|
} else {
|
|
|
|
ClearRecycleCallback();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-12 05:44:44 +04:00
|
|
|
bool
|
|
|
|
TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
|
|
|
|
{
|
2014-12-22 11:49:00 +03:00
|
|
|
MOZ_ASSERT(aForwarder && aForwarder->GetMessageLoop() == mAllocator->GetMessageLoop());
|
2015-10-16 15:46:33 +03:00
|
|
|
if (mActor && !mActor->mDestroyed && mActor->GetForwarder() == aForwarder) {
|
2014-02-10 06:24:27 +04:00
|
|
|
return true;
|
|
|
|
}
|
2015-10-16 15:46:33 +03:00
|
|
|
MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
|
2013-12-12 05:44:53 +04:00
|
|
|
|
2013-12-12 05:44:44 +04:00
|
|
|
SurfaceDescriptor desc;
|
|
|
|
if (!ToSurfaceDescriptor(desc)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-06 09:39:00 +03:00
|
|
|
mActor = static_cast<TextureChild*>(aForwarder->CreateTexture(desc, aForwarder->GetCompositorBackendType(), GetFlags()));
|
2014-01-22 02:06:18 +04:00
|
|
|
MOZ_ASSERT(mActor);
|
2013-12-12 05:44:45 +04:00
|
|
|
mActor->mForwarder = aForwarder;
|
2013-12-12 05:44:55 +04:00
|
|
|
mActor->mTextureClient = this;
|
2015-11-20 16:25:03 +03:00
|
|
|
mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
|
2014-01-22 02:06:18 +04:00
|
|
|
return mActor->IPCOpen();
|
2013-12-12 05:44:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
PTextureChild*
|
|
|
|
TextureClient::GetIPDLActor()
|
|
|
|
{
|
|
|
|
return mActor;
|
|
|
|
}
|
|
|
|
|
2015-08-07 03:27:36 +03:00
|
|
|
static inline gfx::BackendType
|
2015-10-02 09:06:43 +03:00
|
|
|
BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector)
|
2015-08-07 03:27:36 +03:00
|
|
|
{
|
|
|
|
switch (aSelector) {
|
|
|
|
case BackendSelector::Canvas:
|
|
|
|
return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
|
|
|
|
case BackendSelector::Content:
|
2015-10-02 09:06:43 +03:00
|
|
|
return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend);
|
2015-08-07 03:27:36 +03:00
|
|
|
default:
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Unknown backend selector");
|
|
|
|
return gfx::BackendType::NONE;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-07-29 15:16:57 +04:00
|
|
|
// static
|
2015-06-17 17:00:52 +03:00
|
|
|
already_AddRefed<TextureClient>
|
2015-10-06 09:40:13 +03:00
|
|
|
TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
|
2014-07-29 15:16:57 +04:00
|
|
|
gfx::SurfaceFormat aFormat,
|
|
|
|
gfx::IntSize aSize,
|
2015-08-07 03:27:36 +03:00
|
|
|
BackendSelector aSelector,
|
2014-07-29 15:16:57 +04:00
|
|
|
TextureFlags aTextureFlags,
|
|
|
|
TextureAllocationFlags aAllocFlags)
|
2014-03-08 01:34:04 +04:00
|
|
|
{
|
2015-12-14 01:59:00 +03:00
|
|
|
// also test the validity of aAllocator
|
|
|
|
MOZ_ASSERT(aAllocator && aAllocator->IPCOpen());
|
2015-10-30 15:25:29 +03:00
|
|
|
if (!aAllocator || !aAllocator->IPCOpen()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-18 18:59:11 +03:00
|
|
|
if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-02 09:06:43 +03:00
|
|
|
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
|
|
|
|
gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(parentBackend, aSelector);
|
2014-03-18 01:35:20 +04:00
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
TextureData* data = nullptr;
|
2014-03-08 01:34:04 +04:00
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
#if defined(XP_WIN)
|
2014-04-08 16:50:49 +04:00
|
|
|
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
|
|
|
|
#endif
|
|
|
|
|
2014-03-08 01:34:04 +04:00
|
|
|
#ifdef XP_WIN
|
2014-03-18 01:35:20 +04:00
|
|
|
if (parentBackend == LayersBackend::LAYERS_D3D11 &&
|
2015-08-07 03:27:36 +03:00
|
|
|
(moz2DBackend == gfx::BackendType::DIRECT2D ||
|
2015-12-02 22:31:17 +03:00
|
|
|
moz2DBackend == gfx::BackendType::DIRECT2D1_1 ||
|
|
|
|
!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT)) &&
|
2014-07-29 15:16:57 +04:00
|
|
|
aSize.width <= maxTextureSize &&
|
Refactor graphics device initialization on Windows. (bug 1183910 part 1, r=mattwoodrow,bas)
This patch addresses a number of inconsistencies in the device initialization process, as well as simplifying it for future use. All device decisions are now explicitly made up-front during startup, rather than implicitly or on-demand. In addition a number of restrictions have been placed on when we can construct devices.
Full change list:
(1) We no longer attempt to use D3D11 if acceleration is disabled or D3D9 is preferred. This is a departure from our previous behavior, where we would construct these devices but then not use them as a compositor backend.
(2) D3D11 startup no longer creates a content device (this is reserved for D2D initialization).
(3) D2D is only attempted if we managed to create a D3D11 compositor device. This is a departure from previous behavior where if D3D11 was not used for compositing, we could still create its machinery to use D2D as a content backend.
(4) D2D 1.1 initialization is now directly responsible for creating a D3D11 content device.
(5) D2D 1.0 and 1.1 logic have been disentangled for clarity.
(6) UpdateRenderMode() has been split up, so we can update backend prefs out of band with device resets.
(7) mUseGDIFonts and mUseDirectWrite have been removed as their state was confusing. Instead, D2D now depends on DWrite initialization succeeding. If later we fail to get a DWrite font list, we revert our decision to use Direct2D.
(8) Device resets now clear a little more state, including the devices set in Moz2D Factory.
(9) We no longer create a DWrite text analyzer as it was unused.
2015-07-29 02:52:54 +03:00
|
|
|
aSize.height <= maxTextureSize)
|
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
data = DXGITextureData::Create(aSize, aFormat, aAllocFlags);
|
2014-03-08 01:34:04 +04:00
|
|
|
}
|
|
|
|
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
|
2015-08-07 03:27:36 +03:00
|
|
|
moz2DBackend == gfx::BackendType::CAIRO &&
|
2014-03-08 01:34:04 +04:00
|
|
|
aAllocator->IsSameProcess() &&
|
2014-07-29 15:16:57 +04:00
|
|
|
aSize.width <= maxTextureSize &&
|
2015-07-27 18:47:29 +03:00
|
|
|
aSize.height <= maxTextureSize &&
|
2015-11-20 16:25:03 +03:00
|
|
|
NS_IsMainThread() &&
|
|
|
|
gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
|
|
|
|
data = D3D9TextureData::Create(aSize, aFormat, aAllocFlags);
|
2014-03-08 01:34:04 +04:00
|
|
|
}
|
2014-07-11 01:29:40 +04:00
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
if (!data && aFormat == SurfaceFormat::B8G8R8X8 &&
|
2015-08-07 03:27:36 +03:00
|
|
|
moz2DBackend == gfx::BackendType::CAIRO &&
|
2015-07-27 18:47:29 +03:00
|
|
|
NS_IsMainThread()) {
|
2015-11-20 16:25:03 +03:00
|
|
|
data = DIBTextureData::Create(aSize, aFormat, aAllocator);
|
2014-07-11 01:29:40 +04:00
|
|
|
}
|
2014-03-08 01:34:04 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MOZ_X11
|
|
|
|
gfxSurfaceType type =
|
|
|
|
gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
if (!data && parentBackend == LayersBackend::LAYERS_BASIC &&
|
2015-08-07 03:27:36 +03:00
|
|
|
moz2DBackend == gfx::BackendType::CAIRO &&
|
2014-07-29 15:16:57 +04:00
|
|
|
type == gfxSurfaceType::Xlib)
|
2014-03-08 01:34:04 +04:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
|
2014-03-08 01:34:04 +04:00
|
|
|
}
|
|
|
|
#ifdef GL_PROVIDER_GLX
|
2015-11-20 16:25:03 +03:00
|
|
|
if (!data && parentBackend == LayersBackend::LAYERS_OPENGL &&
|
2014-03-08 01:34:04 +04:00
|
|
|
type == gfxSurfaceType::Xlib &&
|
|
|
|
aFormat != SurfaceFormat::A8 &&
|
|
|
|
gl::sGLXLibrary.UseTextureFromPixmap())
|
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
|
2014-03-08 01:34:04 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MOZ_WIDGET_GONK
|
2015-11-20 16:25:03 +03:00
|
|
|
if (!data) {
|
|
|
|
data = GrallocTextureData::CreateForDrawing(aSize, aFormat, moz2DBackend,
|
|
|
|
aAllocator);
|
2014-03-08 01:34:04 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
if (data) {
|
|
|
|
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
|
|
|
|
}
|
|
|
|
|
2014-07-29 15:16:57 +04:00
|
|
|
// Can't do any better than a buffer texture client.
|
2015-10-15 18:53:33 +03:00
|
|
|
return TextureClient::CreateForRawBufferAccess(aAllocator, aFormat, aSize,
|
|
|
|
moz2DBackend, aTextureFlags, aAllocFlags);
|
2014-07-10 15:45:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2015-10-15 18:53:33 +03:00
|
|
|
already_AddRefed<TextureClient>
|
2014-07-10 15:45:40 +04:00
|
|
|
TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
|
|
|
|
gfx::SurfaceFormat aFormat,
|
|
|
|
gfx::IntSize aSize,
|
|
|
|
gfx::BackendType aMoz2DBackend,
|
|
|
|
TextureFlags aTextureFlags,
|
|
|
|
TextureAllocationFlags aAllocFlags)
|
|
|
|
{
|
2015-10-30 15:25:29 +03:00
|
|
|
MOZ_ASSERT(aAllocator->IPCOpen());
|
|
|
|
if (!aAllocator || !aAllocator->IPCOpen()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:03 +03:00
|
|
|
if (aAllocFlags & ALLOC_DISALLOW_BUFFERTEXTURECLIENT) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-18 18:59:11 +03:00
|
|
|
if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-02-17 18:34:37 +03:00
|
|
|
if (aFormat == SurfaceFormat::B8G8R8X8 &&
|
|
|
|
(aAllocFlags != TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK) &&
|
|
|
|
aMoz2DBackend == gfx::BackendType::SKIA) {
|
|
|
|
// skia requires alpha component of RGBX textures to be 255.
|
|
|
|
aAllocFlags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:33 +03:00
|
|
|
TextureData* texData = BufferTextureData::Create(aSize, aFormat, aMoz2DBackend,
|
|
|
|
aTextureFlags, aAllocFlags,
|
|
|
|
aAllocator);
|
|
|
|
if (!texData) {
|
|
|
|
return nullptr;
|
2014-07-10 15:45:40 +04:00
|
|
|
}
|
2015-10-15 18:53:33 +03:00
|
|
|
|
2015-11-20 16:25:00 +03:00
|
|
|
return MakeAndAddRef<TextureClient>(texData, aTextureFlags, aAllocator);
|
2014-07-10 15:45:40 +04:00
|
|
|
}
|
|
|
|
|
2014-07-10 15:48:29 +04:00
|
|
|
// static
|
2015-10-15 18:53:33 +03:00
|
|
|
already_AddRefed<TextureClient>
|
2014-07-10 15:48:29 +04:00
|
|
|
TextureClient::CreateForYCbCr(ISurfaceAllocator* aAllocator,
|
|
|
|
gfx::IntSize aYSize,
|
|
|
|
gfx::IntSize aCbCrSize,
|
|
|
|
StereoMode aStereoMode,
|
|
|
|
TextureFlags aTextureFlags)
|
|
|
|
{
|
2015-10-15 18:53:33 +03:00
|
|
|
// The only reason we allow aAllocator to be null is for gtests
|
|
|
|
MOZ_ASSERT(!aAllocator || aAllocator->IPCOpen());
|
|
|
|
if (aAllocator && !aAllocator->IPCOpen()) {
|
2015-10-30 15:25:29 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-18 18:59:11 +03:00
|
|
|
if (!gfx::Factory::AllowedSurfaceSize(aYSize)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:33 +03:00
|
|
|
TextureData* data = BufferTextureData::CreateForYCbCr(aAllocator, aYSize, aCbCrSize,
|
|
|
|
aStereoMode, aTextureFlags);
|
|
|
|
if (!data) {
|
2014-07-10 15:48:29 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:00 +03:00
|
|
|
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
|
2014-07-10 15:48:29 +04:00
|
|
|
}
|
|
|
|
|
2014-03-08 01:34:04 +04:00
|
|
|
// static
|
2015-10-15 18:53:33 +03:00
|
|
|
already_AddRefed<TextureClient>
|
2015-12-16 21:50:58 +03:00
|
|
|
TextureClient::CreateForYCbCrWithBufferSize(ISurfaceAllocator* aAllocator,
|
|
|
|
gfx::SurfaceFormat aFormat,
|
|
|
|
size_t aSize,
|
|
|
|
TextureFlags aTextureFlags)
|
2014-03-08 01:34:04 +04:00
|
|
|
{
|
2015-12-14 02:01:00 +03:00
|
|
|
// also test the validity of aAllocator
|
|
|
|
MOZ_ASSERT(aAllocator && aAllocator->IPCOpen());
|
2015-10-30 15:25:29 +03:00
|
|
|
if (!aAllocator || !aAllocator->IPCOpen()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-12-16 21:50:58 +03:00
|
|
|
TextureData* data =
|
|
|
|
BufferTextureData::CreateForYCbCrWithBufferSize(aAllocator, aFormat, aSize,
|
|
|
|
aTextureFlags);
|
2015-10-15 18:53:33 +03:00
|
|
|
if (!data) {
|
2014-07-22 16:17:31 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:00 +03:00
|
|
|
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
|
2014-03-08 01:34:04 +04:00
|
|
|
}
|
|
|
|
|
2015-11-20 16:25:00 +03:00
|
|
|
TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, ISurfaceAllocator* aAllocator)
|
|
|
|
: mAllocator(aAllocator)
|
|
|
|
, mActor(nullptr)
|
|
|
|
, mData(aData)
|
|
|
|
, mFlags(aFlags)
|
|
|
|
, mOpenMode(OpenMode::OPEN_NONE)
|
|
|
|
#ifdef DEBUG
|
|
|
|
, mExpectedDtRefs(0)
|
|
|
|
#endif
|
|
|
|
, mIsLocked(false)
|
|
|
|
, mAddedToCompositableClient(false)
|
2015-11-20 16:25:03 +03:00
|
|
|
, mWorkaroundAnnoyingSharedSurfaceLifetimeIssues(false)
|
|
|
|
, mWorkaroundAnnoyingSharedSurfaceOwnershipIssues(false)
|
2014-11-25 22:54:29 +03:00
|
|
|
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
|
2015-11-20 16:25:00 +03:00
|
|
|
, mPoolTracker(nullptr)
|
2014-11-25 22:54:29 +03:00
|
|
|
#endif
|
2015-11-20 18:55:26 +03:00
|
|
|
{
|
2015-11-20 16:25:03 +03:00
|
|
|
mFlags |= mData->GetTextureFlags();
|
2013-12-12 05:44:45 +04:00
|
|
|
}
|
|
|
|
|
2014-03-08 01:34:04 +04:00
|
|
|
bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
|
|
|
|
const gfx::IntRect* aRect,
|
|
|
|
const gfx::IntPoint* aPoint)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(IsLocked());
|
|
|
|
MOZ_ASSERT(aTarget->IsLocked());
|
|
|
|
|
2014-04-10 12:14:28 +04:00
|
|
|
if (!aTarget->CanExposeDrawTarget() || !CanExposeDrawTarget()) {
|
2014-03-08 01:34:04 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<DrawTarget> destinationTarget = aTarget->BorrowDrawTarget();
|
2015-03-09 22:48:20 +03:00
|
|
|
if (!destinationTarget) {
|
|
|
|
gfxWarning() << "TextureClient::CopyToTextureClient (dest) failed in BorrowDrawTarget";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<DrawTarget> sourceTarget = BorrowDrawTarget();
|
2015-03-09 22:48:20 +03:00
|
|
|
if (!sourceTarget) {
|
|
|
|
gfxWarning() << "TextureClient::CopyToTextureClient (src) failed in BorrowDrawTarget";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfx::SourceSurface> source = sourceTarget->Snapshot();
|
2014-03-08 01:34:04 +04:00
|
|
|
destinationTarget->CopySurface(source,
|
|
|
|
aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()),
|
|
|
|
aPoint ? *aPoint : gfx::IntPoint(0, 0));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
void
|
|
|
|
TextureClient::SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter) {
|
|
|
|
mRemoveFromCompositableWaiter = aWaiter;
|
|
|
|
}
|
|
|
|
|
2014-12-18 21:32:45 +03:00
|
|
|
void
|
|
|
|
TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
|
|
|
{
|
|
|
|
aStream << aPrefix;
|
|
|
|
aStream << nsPrintfCString("TextureClient (0x%p)", this).get();
|
|
|
|
AppendToString(aStream, GetSize(), " [size=", "]");
|
|
|
|
AppendToString(aStream, GetFormat(), " [format=", "]");
|
|
|
|
AppendToString(aStream, mFlags, " [flags=", "]");
|
|
|
|
|
|
|
|
#ifdef MOZ_DUMP_PAINTING
|
|
|
|
if (gfxPrefs::LayersDumpTexture() || profiler_feature_active("layersdump")) {
|
|
|
|
nsAutoCString pfx(aPrefix);
|
|
|
|
pfx += " ";
|
|
|
|
|
|
|
|
aStream << "\n" << pfx.get() << "Surface: ";
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfx::DataSourceSurface> dSurf = GetAsSurface();
|
2014-12-18 21:32:45 +03:00
|
|
|
if (dSurf) {
|
|
|
|
aStream << gfxUtils::GetAsLZ4Base64Str(dSurf).get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2015-11-24 21:07:02 +03:00
|
|
|
|
|
|
|
bool
|
2015-10-15 18:53:33 +03:00
|
|
|
UpdateYCbCrTextureClient(TextureClient* aTexture, const PlanarYCbCrData& aData)
|
2015-11-24 21:07:02 +03:00
|
|
|
{
|
2015-10-15 18:53:33 +03:00
|
|
|
MOZ_ASSERT(aTexture);
|
|
|
|
MOZ_ASSERT(aTexture->IsLocked());
|
|
|
|
MOZ_ASSERT(aTexture->GetFormat() == gfx::SurfaceFormat::YUV, "This textureClient can only use YCbCr data");
|
|
|
|
MOZ_ASSERT(!aTexture->IsImmutable());
|
|
|
|
MOZ_ASSERT(aTexture->IsValid());
|
|
|
|
MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
|
2015-11-24 21:07:02 +03:00
|
|
|
|
2015-10-15 18:53:33 +03:00
|
|
|
MappedYCbCrTextureData mapped;
|
|
|
|
if (!aTexture->BorrowMappedYCbCrData(mapped)) {
|
|
|
|
NS_WARNING("Failed to extract YCbCr info!");
|
2015-11-24 21:07:02 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:33 +03:00
|
|
|
MappedYCbCrTextureData srcData;
|
|
|
|
srcData.y.data = aData.mYChannel;
|
|
|
|
srcData.y.size = aData.mYSize;
|
|
|
|
srcData.y.stride = aData.mYStride;
|
|
|
|
srcData.y.skip = aData.mYSkip;
|
|
|
|
srcData.cb.data = aData.mCbChannel;
|
|
|
|
srcData.cb.size = aData.mCbCrSize;
|
|
|
|
srcData.cb.stride = aData.mCbCrStride;
|
|
|
|
srcData.cb.skip = aData.mCbSkip;
|
|
|
|
srcData.cr.data = aData.mCrChannel;
|
|
|
|
srcData.cr.size = aData.mCbCrSize;
|
|
|
|
srcData.cr.stride = aData.mCbCrStride;
|
|
|
|
srcData.cr.skip = aData.mCrSkip;
|
|
|
|
srcData.metadata = nullptr;
|
|
|
|
|
|
|
|
if (!srcData.CopyInto(mapped)) {
|
2015-11-24 21:07:02 +03:00
|
|
|
NS_WARNING("Failed to copy image data!");
|
2015-10-15 18:53:33 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:33 +03:00
|
|
|
if (TextureRequiresLocking(aTexture->GetFlags())) {
|
2015-11-24 21:07:02 +03:00
|
|
|
// We don't have support for proper locking yet, so we'll
|
|
|
|
// have to be immutable instead.
|
2015-10-15 18:53:33 +03:00
|
|
|
aTexture->MarkImmutable();
|
2015-10-15 18:53:33 +03:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-11-24 21:07:02 +03:00
|
|
|
already_AddRefed<SyncObject>
|
|
|
|
SyncObject::CreateSyncObject(SyncHandle aHandle)
|
|
|
|
{
|
|
|
|
if (!aHandle) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef XP_WIN
|
|
|
|
return MakeAndAddRef<SyncObjectD3D11>(aHandle);
|
|
|
|
#else
|
|
|
|
MOZ_ASSERT_UNREACHABLE();
|
|
|
|
return nullptr;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:37 +03:00
|
|
|
already_AddRefed<TextureClient>
|
|
|
|
TextureClient::CreateWithData(TextureData* aData, TextureFlags aFlags, ISurfaceAllocator* aAllocator)
|
|
|
|
{
|
|
|
|
if (!aData) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-11-20 16:25:00 +03:00
|
|
|
return MakeAndAddRef<TextureClient>(aData, aFlags, aAllocator);
|
2015-10-15 18:53:37 +03:00
|
|
|
}
|
|
|
|
|
2015-10-15 18:53:33 +03:00
|
|
|
bool
|
|
|
|
MappedYCbCrChannelData::CopyInto(MappedYCbCrChannelData& aDst)
|
|
|
|
{
|
|
|
|
if (!data || !aDst.data || size != aDst.size) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stride == aDst.stride) {
|
|
|
|
// fast path!
|
|
|
|
// We assume that the padding in the destination is there for alignment
|
|
|
|
// purposes and doesn't contain useful data.
|
|
|
|
memcpy(aDst.data, data, stride * size.height);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < size.height; ++i) {
|
|
|
|
if (aDst.skip == 0 && skip == 0) {
|
|
|
|
// fast-ish path
|
|
|
|
memcpy(aDst.data + i * aDst.stride,
|
|
|
|
data + i * stride,
|
|
|
|
size.width);
|
|
|
|
} else {
|
|
|
|
// slow path
|
|
|
|
uint8_t* src = data + i * stride;
|
|
|
|
uint8_t* dst = aDst.data + i * aDst.stride;
|
|
|
|
for (int32_t j = 0; j < size.width; ++j) {
|
|
|
|
*dst = *src;
|
|
|
|
src += 1 + skip;
|
|
|
|
dst += 1 + aDst.skip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace layers
|
|
|
|
} // namespace mozilla
|