Backed out 6 changesets (bug 1632249) for causing bustages in CanvasRenderingContext2D.cpp

CLOSED TREE

Backed out changeset c93972b05d4f (bug 1632249)
Backed out changeset 04f5127c85d5 (bug 1632249)
Backed out changeset b15d91e64a25 (bug 1632249)
Backed out changeset 71ad2ed8e9ba (bug 1632249)
Backed out changeset 6e9a89ead3a5 (bug 1632249)
Backed out changeset dd00e2da3a0f (bug 1632249)
This commit is contained in:
Mihai Alexandru Michis 2020-06-11 02:43:35 +03:00
Родитель b3cbb2b28e
Коммит 59ad7ed333
108 изменённых файлов: 6239 добавлений и 1923 удалений

Просмотреть файл

@ -11,7 +11,7 @@
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/layers/CanvasRenderer.h"
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/RefPtr.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/Unused.h"
@ -217,7 +217,7 @@ class EncodingRunnable : public Runnable {
nsresult ImageEncoder::ExtractData(nsAString& aType, const nsAString& aOptions,
const nsIntSize aSize, bool aUsePlaceholder,
nsICanvasRenderingContextInternal* aContext,
layers::CanvasRenderer* aRenderer,
layers::AsyncCanvasRenderer* aRenderer,
nsIInputStream** aStream) {
nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
if (!encoder) {
@ -290,7 +290,7 @@ nsresult ImageEncoder::ExtractDataInternal(
const nsAString& aType, const nsAString& aOptions, uint8_t* aImageBuffer,
int32_t aFormat, const nsIntSize aSize, bool aUsePlaceholder,
layers::Image* aImage, nsICanvasRenderingContextInternal* aContext,
layers::CanvasRenderer* aRenderer, nsIInputStream** aStream,
layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream,
imgIEncoder* aEncoder) {
if (aSize.IsEmpty()) {
return NS_ERROR_INVALID_ARG;
@ -313,32 +313,9 @@ nsresult ImageEncoder::ExtractDataInternal(
rv = aContext->GetInputStream(encoderType.get(), aOptions,
getter_AddRefs(imgStream));
} else if (aRenderer && !aUsePlaceholder) {
MOZ_CRASH("unused?");
const NS_ConvertUTF16toUTF8 encoderType(aType);
if (BufferSizeFromDimensions(aSize.width, aSize.height, 4) == 0) {
return NS_ERROR_INVALID_ARG;
}
const auto snapshot = aRenderer->BorrowSnapshot();
if (!snapshot) {
return NS_ERROR_OUT_OF_MEMORY;
}
const RefPtr<DataSourceSurface> data = snapshot->mSurf->GetDataSurface();
if (!data) {
return NS_ERROR_OUT_OF_MEMORY;
}
{
DataSourceSurface::MappedSurface map;
if (!data->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
return NS_ERROR_INVALID_ARG;
}
rv = aEncoder->InitFromData(map.mData, aSize.width * aSize.height * 4,
aSize.width, aSize.height, aSize.width * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions);
data->Unmap();
}
NS_ConvertUTF16toUTF8 encoderType(aType);
rv = aRenderer->GetInputStream(encoderType.get(), aOptions,
getter_AddRefs(imgStream));
} else if (aImage && !aUsePlaceholder) {
// It is safe to convert PlanarYCbCr format from YUV to RGB off-main-thread.
// Other image formats could have problem to convert format off-main-thread.

Просмотреть файл

@ -20,7 +20,7 @@ class nsICanvasRenderingContextInternal;
namespace mozilla {
namespace layers {
class CanvasRenderer;
class AsyncCanvasRenderer;
class Image;
} // namespace layers
@ -40,7 +40,7 @@ class ImageEncoder {
static nsresult ExtractData(nsAString& aType, const nsAString& aOptions,
const nsIntSize aSize, bool aUsePlaceholder,
nsICanvasRenderingContextInternal* aContext,
layers::CanvasRenderer* aRenderer,
layers::AsyncCanvasRenderer* aRenderer,
nsIInputStream** aStream);
// Extracts data asynchronously. aType may change to "image/png" if we had to
@ -86,7 +86,7 @@ class ImageEncoder {
const nsAString& aType, const nsAString& aOptions, uint8_t* aImageBuffer,
int32_t aFormat, const nsIntSize aSize, bool aUsePlaceholder,
layers::Image* aImage, nsICanvasRenderingContextInternal* aContext,
layers::CanvasRenderer* aRenderer, nsIInputStream** aStream,
layers::AsyncCanvasRenderer* aRenderer, nsIInputStream** aStream,
imgIEncoder* aEncoder);
// Creates and returns an encoder instance of the type specified in aType.

Просмотреть файл

@ -780,6 +780,42 @@ CanvasShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
class CanvasRenderingContext2DUserData : public LayerUserData {
public:
explicit CanvasRenderingContext2DUserData(CanvasRenderingContext2D* aContext)
: mContext(aContext) {
aContext->mUserDatas.AppendElement(this);
}
~CanvasRenderingContext2DUserData() {
if (mContext) {
mContext->mUserDatas.RemoveElement(this);
}
}
static void PreTransactionCallback(void* aData) {
CanvasRenderingContext2D* context =
static_cast<CanvasRenderingContext2D*>(aData);
if (!context || !context->mTarget) return;
context->OnStableState();
}
static void DidTransactionCallback(void* aData) {
CanvasRenderingContext2D* context =
static_cast<CanvasRenderingContext2D*>(aData);
if (context) {
context->MarkContextClean();
}
}
bool IsForContext(CanvasRenderingContext2D* aContext) {
return mContext == aContext;
}
void Forget() { mContext = nullptr; }
private:
CanvasRenderingContext2D* mContext;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasRenderingContext2D)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasRenderingContext2D)
@ -943,7 +979,10 @@ CanvasRenderingContext2D::~CanvasRenderingContext2D() {
RemovePostRefreshObserver();
RemoveShutdownObserver();
Reset();
// Drop references from all CanvasRenderingContext2DUserData to this context
for (uint32_t i = 0; i < mUserDatas.Length(); ++i) {
mUserDatas[i]->Forget();
}
sNumLivingContexts--;
if (!sNumLivingContexts) {
NS_IF_RELEASE(sErrorTarget);
@ -5307,13 +5346,6 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::CreateImageData(
static uint8_t g2DContextLayerUserData;
void CanvasRenderingContext2D::OnBeforePaintTransaction() {
if (!mTarget) return;
OnStableState();
}
void CanvasRenderingContext2D::OnDidPaintTransaction() { MarkContextClean(); }
already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
nsDisplayListBuilder* aBuilder, Layer* aOldLayer, LayerManager* aManager) {
if (mOpaque) {
@ -5334,8 +5366,20 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
}
if (!mResetLayer && aOldLayer) {
RefPtr<Layer> ret = aOldLayer;
return ret.forget();
auto userData = static_cast<CanvasRenderingContext2DUserData*>(
aOldLayer->GetUserData(&g2DContextLayerUserData));
CanvasInitializeData data;
data.mBufferProvider = mBufferProvider;
if (userData && userData->IsForContext(this) &&
static_cast<CanvasLayer*>(aOldLayer)
->CreateOrGetCanvasRenderer()
->IsDataValid(data)) {
RefPtr<Layer> ret = aOldLayer;
return ret.forget();
}
}
RefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
@ -5346,8 +5390,22 @@ already_AddRefed<Layer> CanvasRenderingContext2D::GetCanvasLayer(
MarkContextClean();
return nullptr;
}
CanvasRenderingContext2DUserData* userData = nullptr;
// Make the layer tell us whenever a transaction finishes (including
// the current transaction), so we can clear our invalidation state and
// start invalidating again. We need to do this for all layers since
// callers of DrawWindow may be expecting to receive normal invalidation
// notifications after this paint.
const auto canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
// The layer will be destroyed when we tear down the presentation
// (at the latest), at which time this userData will be destroyed,
// releasing the reference to the element.
// The userData will receive DidTransactionCallbacks, which flush the
// the invalidation state to indicate that the canvas is up to date.
userData = new CanvasRenderingContext2DUserData(this);
canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
InitializeCanvasRenderer(aBuilder, canvasRenderer);
uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
canvasLayer->SetContentFlags(flags);
@ -5378,12 +5436,12 @@ bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
return false;
}
auto renderer = aCanvasData->GetCanvasRenderer();
CanvasRenderer* renderer = aCanvasData->GetCanvasRenderer();
if (!mResetLayer && renderer) {
CanvasRendererData data;
data.mContext = mSharedPtrPtr;
data.mSize = GetSize();
CanvasInitializeData data;
data.mBufferProvider = mBufferProvider;
if (renderer->IsDataValid(data)) {
return true;
@ -5404,11 +5462,15 @@ bool CanvasRenderingContext2D::UpdateWebRenderCanvasData(
bool CanvasRenderingContext2D::InitializeCanvasRenderer(
nsDisplayListBuilder* aBuilder, CanvasRenderer* aRenderer) {
CanvasRendererData data;
data.mContext = mSharedPtrPtr;
CanvasInitializeData data;
data.mSize = GetSize();
data.mIsOpaque = mOpaque;
data.mDoPaintCallbacks = true;
data.mHasAlpha = !mOpaque;
data.mPreTransCallback =
CanvasRenderingContext2DUserData::PreTransactionCallback;
data.mPreTransCallbackData = this;
data.mDidTransCallback =
CanvasRenderingContext2DUserData::DidTransactionCallback;
data.mDidTransCallbackData = this;
if (!mBufferProvider) {
// Force the creation of a buffer provider.
@ -5420,6 +5482,8 @@ bool CanvasRenderingContext2D::InitializeCanvasRenderer(
}
}
data.mBufferProvider = mBufferProvider;
aRenderer->Initialize(data);
aRenderer->SetDirty();
return true;

Просмотреть файл

@ -56,6 +56,7 @@ template <typename T>
class Optional;
struct CanvasBidiProcessor;
class CanvasRenderingContext2DUserData;
class CanvasDrawObserver;
class CanvasShutdownObserver;
@ -86,12 +87,6 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
return mCanvasElement->GetOriginalCanvas();
}
void OnBeforePaintTransaction() override;
void OnDidPaintTransaction() override;
layers::PersistentBufferProvider* GetBufferProvider() override {
return mBufferProvider;
}
void Save() override;
void Restore() override;
void Scale(double aX, double aY, mozilla::ErrorResult& aError) override;
@ -496,6 +491,8 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
}
}
friend class CanvasRenderingContext2DUserData;
virtual UniquePtr<uint8_t[]> GetImageBuffer(int32_t* aFormat) override;
// Given a point, return hit region ID if it exists
@ -723,6 +720,8 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
bool mHasPendingStableStateCallback;
nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
// If mCanvasElement is not provided, then a docshell is
nsCOMPtr<nsIDocShell> mDocShell;

Просмотреть файл

@ -398,43 +398,82 @@ ReturnType ClientWebGLContext::Run(Args&&... aArgs) const {
// ------------------------- Composition, etc -------------------------
void ClientWebGLContext::OnBeforePaintTransaction() {
const RefPtr<layers::ImageBridgeChild> imageBridge =
layers::ImageBridgeChild::GetSingleton();
static uint8_t gWebGLLayerUserData;
auto texType = layers::TextureType::Unknown;
if (imageBridge) {
texType = layers::PreferredCanvasTextureType(*imageBridge);
class WebGLContextUserData : public LayerUserData {
public:
explicit WebGLContextUserData(HTMLCanvasElement* canvas) : mCanvas(canvas) {}
/* PreTransactionCallback gets called by the Layers code every time the
* WebGL canvas is going to be composited.
*/
static void PreTransactionCallback(void* data) {
ClientWebGLContext* webgl = static_cast<ClientWebGLContext*>(data);
// Prepare the context for composition
webgl->BeginComposition();
}
Present(nullptr, texType);
/** DidTransactionCallback gets called by the Layers code everytime the WebGL
* canvas gets composite, so it really is the right place to put actions that
* have to be performed upon compositing
*/
static void DidTransactionCallback(void* data) {
ClientWebGLContext* webgl = static_cast<ClientWebGLContext*>(data);
// Clean up the context after composition
webgl->EndComposition();
}
private:
RefPtr<HTMLCanvasElement> mCanvas;
};
void ClientWebGLContext::BeginComposition() {
// When running single-process WebGL, Present needs to be called in
// BeginComposition so that it is done _before_ the CanvasRenderer to
// Update attaches it for composition.
// When running cross-process WebGL, Present needs to be called in
// EndComposition so that it happens _after_ the OOPCanvasRenderer's
// Update tells it what CompositableHost to use,
if (!mNotLost) return;
if (mNotLost->inProcess) {
WEBGL_BRIDGE_LOGI("[%p] Presenting", this);
Run<RPROC(Present)>();
}
}
void ClientWebGLContext::EndComposition() {
if (!mNotLost) return;
if (mNotLost->outOfProcess) {
WEBGL_BRIDGE_LOGI("[%p] Presenting", this);
Run<RPROC(Present)>();
}
// Mark ourselves as no longer invalidated.
MarkContextClean();
}
// -
void ClientWebGLContext::Present() { Run<RPROC(Present)>(); }
void ClientWebGLContext::Present(WebGLFramebufferJS* const fb,
const layers::TextureType type) {
if (!mIsCanvasDirty && !fb) return;
mIsCanvasDirty = false;
void ClientWebGLContext::ClearVRFrame() const { Run<RPROC(ClearVRFrame)>(); }
Run<RPROC(Present)>(fb ? fb->mId : 0, type);
RefPtr<layers::SharedSurfaceTextureClient> ClientWebGLContext::GetVRFrame(
const WebGLFramebufferJS* fb) const {
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
if (!notLost) return nullptr;
const auto& inProcessContext = notLost->inProcess;
if (inProcessContext) {
return inProcessContext->GetVRFrame(fb ? fb->mId : 0);
}
MOZ_ASSERT_UNREACHABLE("TODO: Remote GetVRFrame");
return nullptr;
}
Maybe<layers::SurfaceDescriptor> ClientWebGLContext::GetFrontBuffer(
WebGLFramebufferJS* const fb, const layers::TextureType type) {
return Run<RPROC(GetFrontBuffer)>(fb ? fb->mId : 0, type);
}
// -
already_AddRefed<layers::Layer> ClientWebGLContext::GetCanvasLayer(
nsDisplayListBuilder* builder, Layer* oldLayer, LayerManager* manager) {
if (!mResetLayer && oldLayer) {
if (!mResetLayer && oldLayer && oldLayer->HasUserData(&gWebGLLayerUserData)) {
RefPtr<layers::Layer> ret = oldLayer;
return ret.forget();
}
@ -447,7 +486,14 @@ already_AddRefed<layers::Layer> ClientWebGLContext::GetCanvasLayer(
return nullptr;
}
const auto canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
WebGLContextUserData* userData = nullptr;
if (builder->IsPaintingToWindow() && mCanvasElement) {
userData = new WebGLContextUserData(mCanvasElement);
}
canvasLayer->SetUserData(&gWebGLLayerUserData, userData);
CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
if (!InitializeCanvasRenderer(builder, canvasRenderer)) return nullptr;
uint32_t flags = 0;
@ -457,6 +503,7 @@ already_AddRefed<layers::Layer> ClientWebGLContext::GetCanvasLayer(
canvasLayer->SetContentFlags(flags);
mResetLayer = false;
return canvasLayer.forget();
}
@ -486,20 +533,55 @@ bool ClientWebGLContext::InitializeCanvasRenderer(
const FuncScope funcScope(*this, "<InitializeCanvasRenderer>");
if (IsContextLost()) return false;
CanvasRendererData data;
data.mContext = mSharedPtrPtr;
data.mOriginPos = gl::OriginPos::BottomLeft;
Maybe<ICRData> icrData =
Run<RPROC(InitializeCanvasRenderer)>(GetCompositorBackendType());
const auto& options = *mInitialOptions;
const auto& size = DrawingBufferSize();
data.mIsOpaque = !options.alpha;
data.mIsAlphaPremult = !options.alpha || options.premultipliedAlpha;
data.mSize = {size.x, size.y};
if (aBuilder->IsPaintingToWindow() && mCanvasElement) {
data.mDoPaintCallbacks = true;
if (!icrData) {
return false;
}
mSurfaceInfo = *icrData;
CanvasInitializeData data;
if (aBuilder->IsPaintingToWindow() && mCanvasElement) {
// Make the layer tell us whenever a transaction finishes (including
// the current transaction), so we can clear our invalidation state and
// start invalidating again. We need to do this for the layer that is
// being painted to a window (there shouldn't be more than one at a time,
// and if there is, flushing the invalidation state more often than
// necessary is harmless).
// The layer will be destroyed when we tear down the presentation
// (at the latest), at which time this userData will be destroyed,
// releasing the reference to the element.
// The userData will receive DidTransactionCallbacks, which flush the
// the invalidation state to indicate that the canvas is up to date.
data.mPreTransCallback = WebGLContextUserData::PreTransactionCallback;
data.mPreTransCallbackData = this;
data.mDidTransCallback = WebGLContextUserData::DidTransactionCallback;
data.mDidTransCallbackData = this;
}
MOZ_ASSERT(mCanvasElement); // TODO: What to do here? Is this about
// OffscreenCanvas?
if (!mNotLost) return false;
if (mNotLost->outOfProcess) {
data.mOOPRenderer = mCanvasElement->GetOOPCanvasRenderer();
MOZ_ASSERT(data.mOOPRenderer);
MOZ_ASSERT((!data.mOOPRenderer->mContext) ||
(data.mOOPRenderer->mContext == this));
data.mOOPRenderer->mContext = this;
} else {
MOZ_ASSERT(mNotLost->inProcess);
data.mGLContext = mNotLost->inProcess->GetWebGLContext()->gl;
}
data.mHasAlpha = mSurfaceInfo.hasAlpha;
data.mIsGLAlphaPremult = mSurfaceInfo.isPremultAlpha || !data.mHasAlpha;
data.mSize = mSurfaceInfo.size;
aRenderer->Initialize(data);
aRenderer->SetDirty();
return true;
@ -590,21 +672,13 @@ ClientWebGLContext::SetDimensions(const int32_t signedWidth,
if (!size.y) {
size.y = 1;
}
const auto prevRequestedSize = mRequestedSize;
mRequestedSize = size;
mResetLayer = true; // Always treat this as resize.
if (mNotLost) {
auto& state = State();
auto curSize = prevRequestedSize;
if (state.mDrawingBufferSize) {
curSize = *state.mDrawingBufferSize;
}
if (size == curSize) return NS_OK; // MUST skip no-op resize
state.mDrawingBufferSize = Nothing();
Run<RPROC(Resize)>(size);
MarkCanvasDirty();
@ -717,7 +791,6 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
return false;
}
mNotLost = pNotLost;
MarkCanvasDirty();
// Init state
const auto& limits = Limits();
@ -849,67 +922,6 @@ already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot(
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
auto ret = BackBufferSnapshot();
if (!ret) return nullptr;
// -
const auto& options = mNotLost->info.options;
auto srcAlphaType = gfxAlphaType::Opaque;
if (options.alpha) {
if (options.premultipliedAlpha) {
srcAlphaType = gfxAlphaType::Premult;
} else {
srcAlphaType = gfxAlphaType::NonPremult;
}
}
if (out_alphaType) {
*out_alphaType = srcAlphaType;
} else {
// Expects Opaque or Premult
if (srcAlphaType == gfxAlphaType::NonPremult) {
const auto nonPremultSurf = ret;
const auto& size = nonPremultSurf->GetSize();
const auto format = nonPremultSurf->GetFormat();
ret = gfx::Factory::CreateDataSourceSurface(size, format, /*zero=*/false);
gfxUtils::PremultiplyDataSurface(nonPremultSurf, ret);
}
}
return ret.forget();
}
RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
const bool requireAlphaPremult) {
const FuncScope funcScope(*this, "<GetSurfaceSnapshot>");
if (IsContextLost()) return nullptr;
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
const auto& options = mNotLost->info.options;
auto snapshot = Run<RPROC(GetFrontBufferSnapshot)>();
if (!snapshot) return nullptr;
if (requireAlphaPremult && options.alpha && !options.premultipliedAlpha) {
const auto nonPremultSurf = snapshot;
const auto& size = nonPremultSurf->GetSize();
const auto format = nonPremultSurf->GetFormat();
snapshot =
gfx::Factory::CreateDataSourceSurface(size, format, /*zero=*/false);
gfxUtils::PremultiplyDataSurface(nonPremultSurf, snapshot);
}
return snapshot;
}
RefPtr<gfx::DataSourceSurface> ClientWebGLContext::BackBufferSnapshot() {
if (IsContextLost()) return nullptr;
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
const auto& options = mNotLost->info.options;
const auto& state = State();
@ -958,31 +970,64 @@ RefPtr<gfx::DataSourceSurface> ClientWebGLContext::BackBufferSnapshot() {
MOZ_ASSERT(static_cast<uint32_t>(map.GetStride()) == stride);
const auto desc = webgl::ReadPixelsDesc{{0, 0}, size};
const auto range = Range<uint8_t>(map.GetData(), stride * size.y);
DoReadPixels(desc, range);
auto view = RawBufferView(range);
const auto begin = range.begin().get();
std::vector<uint8_t> temp;
temp.resize(stride);
for (const auto i : IntegerRange(size.y / 2)) {
const auto top = begin + stride * i;
const auto bottom = begin + stride * (size.y - 1 - i);
memcpy(temp.data(), top, stride);
memcpy(top, bottom, stride);
gfxUtils::ConvertBGRAtoRGBA(top, stride);
memcpy(bottom, temp.data(), stride);
gfxUtils::ConvertBGRAtoRGBA(bottom, stride);
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
if (!notLost) return nullptr;
const auto& inProcessContext = notLost->inProcess;
if (inProcessContext) {
inProcessContext->ReadPixels(desc, view);
} else {
MOZ_ASSERT_UNREACHABLE("TODO: Remote GetSurfaceSnapshot");
}
// -
if (size.y % 2) {
const auto middle = begin + stride * (size.y / 2);
gfxUtils::ConvertBGRAtoRGBA(middle, stride);
const auto swapRowRedBlue = [&](uint8_t* const row) {
for (const auto x : IntegerRange(size.x)) {
std::swap(row[4 * x], row[4 * x + 2]);
}
};
std::vector<uint8_t> tempRow(stride);
for (const auto srcY : IntegerRange(size.y / 2)) {
const auto dstY = size.y - 1 - srcY;
const auto srcRow = (range.begin() + (stride * srcY)).get();
const auto dstRow = (range.begin() + (stride * dstY)).get();
memcpy(tempRow.data(), dstRow, stride);
memcpy(dstRow, srcRow, stride);
swapRowRedBlue(dstRow);
memcpy(srcRow, tempRow.data(), stride);
swapRowRedBlue(srcRow);
}
if (size.y & 1) {
const auto midY = size.y / 2; // size.y = 3 => midY = 1
const auto midRow = (range.begin() + (stride * midY)).get();
swapRowRedBlue(midRow);
}
}
return surf;
gfxAlphaType srcAlphaType;
if (!options.alpha) {
srcAlphaType = gfxAlphaType::Opaque;
} else if (options.premultipliedAlpha) {
srcAlphaType = gfxAlphaType::Premult;
} else {
srcAlphaType = gfxAlphaType::NonPremult;
}
if (out_alphaType) {
*out_alphaType = srcAlphaType;
} else {
// Expects Opaque or Premult
if (srcAlphaType == gfxAlphaType::NonPremult) {
gfxUtils::PremultiplyDataSurface(surf, surf);
}
}
return surf.forget();
}
UniquePtr<uint8_t[]> ClientWebGLContext::GetImageBuffer(int32_t* out_format) {
@ -4048,12 +4093,7 @@ void ClientWebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
{format, type},
state.mPixelPackState};
const auto range = Range<uint8_t>(bytes, byteLen);
DoReadPixels(desc, range);
}
void ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
const Range<uint8_t> dest) const {
auto view = RawBufferView(dest);
auto view = RawBufferView(range);
const auto notLost =
mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.

Просмотреть файл

@ -45,6 +45,10 @@ namespace dom {
class WebGLChild;
}
namespace layers {
class SharedSurfaceTextureClient;
}
namespace webgl {
class TexUnpackBlob;
class TexUnpackBytes;
@ -694,6 +698,7 @@ struct TexImageSourceAdapter final : public TexImageSource {
class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
public nsWrapperCache,
public SupportsWeakPtr<ClientWebGLContext> {
friend class WebGLContextUserData;
friend class webgl::ObjectJS;
friend class webgl::ProgramKeepAlive;
friend class webgl::ShaderKeepAlive;
@ -719,11 +724,6 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
public:
const bool mIsWebGL2;
private:
bool mIsCanvasDirty = false;
uvec2 mRequestedSize = {};
public:
explicit ClientWebGLContext(bool webgl2);
private:
@ -768,12 +768,7 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
void ThrowEvent_WebGLContextCreationError(const std::string&) const;
public:
void MarkCanvasDirty();
void MarkContextClean() override {}
void OnBeforePaintTransaction() override;
ClientWebGLContext* AsWebgl() override { return this; }
void MarkCanvasDirty() { Invalidate(); }
mozilla::dom::WebGLChild* GetChild() const {
if (!mNotLost) return nullptr;
@ -910,6 +905,7 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
bool IsContextCleanForFrameCapture() override {
return !mCapturedFrameInvalidated;
}
void MarkContextClean() override { mInvalidated = false; }
void MarkContextCleanForFrameCapture() override {
mCapturedFrameInvalidated = false;
}
@ -968,9 +964,12 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
// ------
void Invalidate();
protected:
layers::LayersBackend GetCompositorBackendType() const;
bool mInvalidated = false;
bool mCapturedFrameInvalidated = false;
// -------------------------------------------------------------------------
@ -992,22 +991,23 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
}
void GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);
void Present(WebGLFramebufferJS*, layers::TextureType);
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(WebGLFramebufferJS*,
layers::TextureType);
RefPtr<gfx::SourceSurface> GetFrontBufferSnapshot(
bool requireAlphaPremult = true) override;
void Present();
RefPtr<layers::SharedSurfaceTextureClient> GetVRFrame(
const WebGLFramebufferJS*) const;
void ClearVRFrame() const;
private:
RefPtr<gfx::DataSourceSurface> BackBufferSnapshot();
void DoReadPixels(const webgl::ReadPixelsDesc&, Range<uint8_t>) const;
uvec2 DrawingBufferSize();
ICRData mSurfaceInfo;
void AfterDrawCall() {
if (!mNotLost) return;
const auto& state = State();
if (!state.mBoundDrawFb) {
MarkCanvasDirty();
const bool isBackbuffer = !state.mBoundDrawFb;
if (isBackbuffer) {
Invalidate();
}
}
@ -1699,6 +1699,7 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
unpackType, anySrc, out_error);
}
// =========================================================================
// ------------------------ Uniforms and attributes ------------------------
public:
void GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,

Просмотреть файл

@ -317,7 +317,7 @@ class ClientWebGLExtensionExplicitPresent : public ClientWebGLExtensionBase {
AutoJsWarning("present: Extension is `invalidated`.");
return;
}
mContext->OnBeforePaintTransaction();
mContext->Present();
}
};

Просмотреть файл

@ -7,7 +7,7 @@
#include "CompositableHost.h"
#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "MozFramebuffer.h"
#include "TexUnpackBlob.h"
@ -106,9 +106,9 @@ void HostWebGLContext::JsWarning(const std::string& text) const {
(void)mOwnerData.outOfProcess->mParent.SendJsWarning(text);
}
Maybe<layers::SurfaceDescriptor> HostWebGLContext::GetFrontBuffer(
const ObjectId fb, const layers::TextureType t) const {
return mContext->GetFrontBuffer(AutoResolve(fb), t);
RefPtr<layers::SharedSurfaceTextureClient> HostWebGLContext::GetVRFrame(
ObjectId id) const {
return mContext->GetVRFrame(AutoResolve(id));
}
//////////////////////////////////////////////

Просмотреть файл

@ -184,14 +184,11 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
mContext->SetCompositableHost(compositableHost);
}
void Present(const ObjectId fb, const layers::TextureType t) const {
return (void)mContext->Present(AutoResolve(fb), t);
}
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(ObjectId fb,
layers::TextureType) const;
void Present() { mContext->Present(); }
void ClearVRFrame() const { mContext->ClearVRFrame(); }
RefPtr<gfx::DataSourceSurface> GetFrontBufferSnapshot() const {
return mContext->GetFrontBufferSnapshot();
Maybe<ICRData> InitializeCanvasRenderer(layers::LayersBackend backend) {
return mContext->InitializeCanvasRenderer(backend);
}
void Resize(const uvec2& size) { return mContext->Resize(size); }
@ -788,6 +785,10 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
void OnLostContext();
void OnRestoredContext();
// Etc
public:
RefPtr<layers::SharedSurfaceTextureClient> GetVRFrame(ObjectId id) const;
protected:
WebGL2Context* GetWebGL2Context() const {
MOZ_RELEASE_ASSERT(mContext->IsWebGL2(), "Requires WebGL2 context");

Просмотреть файл

@ -9,7 +9,7 @@
#include "mozilla/dom/OffscreenCanvasBinding.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/layers/CanvasRenderer.h"
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/CanvasClient.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/Telemetry.h"
@ -22,7 +22,7 @@ namespace mozilla {
namespace dom {
OffscreenCanvasCloneData::OffscreenCanvasCloneData(
layers::CanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight,
layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight,
layers::LayersBackend aCompositorBackend, bool aNeutered, bool aIsWriteOnly)
: mRenderer(aRenderer),
mWidth(aWidth),
@ -36,7 +36,7 @@ OffscreenCanvasCloneData::~OffscreenCanvasCloneData() = default;
OffscreenCanvas::OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth,
uint32_t aHeight,
layers::LayersBackend aCompositorBackend,
layers::CanvasRenderer* aRenderer)
layers::AsyncCanvasRenderer* aRenderer)
: DOMEventTargetHelper(aGlobal),
mAttrDirty(false),
mNeutered(false),
@ -66,20 +66,19 @@ void OffscreenCanvas::ClearResources() {
if (mCanvasClient) {
mCanvasClient->Clear();
MOZ_CRASH("todo");
// if (mCanvasRenderer) {
// nsCOMPtr<nsISerialEventTarget> activeTarget =
// mCanvasRenderer->GetActiveEventTarget();
// MOZ_RELEASE_ASSERT(activeTarget,
// "GFX: failed to get active event target.");
// bool current;
// activeTarget->IsOnCurrentThread(&current);
// MOZ_RELEASE_ASSERT(current, "GFX: active thread is not current
// thread."); mCanvasRenderer->SetCanvasClient(nullptr);
// mCanvasRenderer->mContext = nullptr;
// mCanvasRenderer->mGLContext = nullptr;
// mCanvasRenderer->ResetActiveEventTarget();
//}
if (mCanvasRenderer) {
nsCOMPtr<nsISerialEventTarget> activeTarget =
mCanvasRenderer->GetActiveEventTarget();
MOZ_RELEASE_ASSERT(activeTarget,
"GFX: failed to get active event target.");
bool current;
activeTarget->IsOnCurrentThread(&current);
MOZ_RELEASE_ASSERT(current, "GFX: active thread is not current thread.");
mCanvasRenderer->SetCanvasClient(nullptr);
mCanvasRenderer->mContext = nullptr;
mCanvasRenderer->mGLContext = nullptr;
mCanvasRenderer->ResetActiveEventTarget();
}
mCanvasClient = nullptr;
}
@ -116,7 +115,7 @@ already_AddRefed<nsISupports> OffscreenCanvas::GetContext(
}
if (mCanvasRenderer) {
// mCanvasRenderer->SetContextType(contextType);
mCanvasRenderer->SetContextType(contextType);
if (contextType == CanvasContextType::WebGL1 ||
contextType == CanvasContextType::WebGL2) {
MOZ_ASSERT_UNREACHABLE("WebGL OffscreenCanvas not yet supported.");
@ -135,8 +134,7 @@ ImageContainer* OffscreenCanvas::GetImageContainer() {
if (!mCanvasRenderer) {
return nullptr;
}
// return mCanvasRenderer->GetImageContainer();
MOZ_CRASH("todo");
return mCanvasRenderer->GetImageContainer();
}
already_AddRefed<nsICanvasRenderingContextInternal>
@ -154,36 +152,34 @@ void OffscreenCanvas::CommitFrameToCompositor() {
// So, just bail out.
return;
}
MOZ_CRASH("todo");
// The attributes has changed, we have to notify main
// thread to change canvas size.
if (mAttrDirty) {
MOZ_CRASH("todo");
// if (mCanvasRenderer) {
// mCanvasRenderer->SetWidth(mWidth);
// mCanvasRenderer->SetHeight(mHeight);
// mCanvasRenderer->NotifyElementAboutAttributesChanged();
//}
if (mCanvasRenderer) {
mCanvasRenderer->SetWidth(mWidth);
mCanvasRenderer->SetHeight(mHeight);
mCanvasRenderer->NotifyElementAboutAttributesChanged();
}
mAttrDirty = false;
}
// CanvasContextType contentType = mCanvasRenderer->GetContextType();
// if (mCurrentContext && (contentType == CanvasContextType::WebGL1 ||
// contentType == CanvasContextType::WebGL2)) {
// MOZ_ASSERT_UNREACHABLE("WebGL OffscreenCanvas not yet supported.");
// return;
//}
// if (mCurrentContext && (contentType == CanvasContextType::WebGPU)) {
// MOZ_ASSERT_UNREACHABLE("WebGPU OffscreenCanvas not yet supported.");
// return;
//}
CanvasContextType contentType = mCanvasRenderer->GetContextType();
if (mCurrentContext && (contentType == CanvasContextType::WebGL1 ||
contentType == CanvasContextType::WebGL2)) {
MOZ_ASSERT_UNREACHABLE("WebGL OffscreenCanvas not yet supported.");
return;
}
if (mCurrentContext && (contentType == CanvasContextType::WebGPU)) {
MOZ_ASSERT_UNREACHABLE("WebGPU OffscreenCanvas not yet supported.");
return;
}
// if (mCanvasRenderer && mCanvasRenderer->mGLContext) {
// mCanvasRenderer->NotifyElementAboutInvalidation();
// ImageBridgeChild::GetSingleton()->UpdateAsyncCanvasRenderer(
// mCanvasRenderer);
//}
if (mCanvasRenderer && mCanvasRenderer->mGLContext) {
mCanvasRenderer->NotifyElementAboutInvalidation();
ImageBridgeChild::GetSingleton()->UpdateAsyncCanvasRenderer(
mCanvasRenderer);
}
}
OffscreenCanvasCloneData* OffscreenCanvas::ToCloneData() {

Просмотреть файл

@ -21,8 +21,8 @@ namespace mozilla {
class ErrorResult;
namespace layers {
class AsyncCanvasRenderer;
class CanvasClient;
class CanvasRenderer;
class ImageContainer;
} // namespace layers
@ -35,13 +35,13 @@ class ImageBitmap;
// Canvas to worker thread directly. Thus, we create this helper class and
// store necessary data in it then pass it to worker thread.
struct OffscreenCanvasCloneData final {
OffscreenCanvasCloneData(layers::CanvasRenderer* aRenderer, uint32_t aWidth,
uint32_t aHeight,
OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer,
uint32_t aWidth, uint32_t aHeight,
layers::LayersBackend aCompositorBackend,
bool aNeutered, bool aIsWriteOnly);
~OffscreenCanvasCloneData();
RefPtr<layers::CanvasRenderer> mRenderer;
RefPtr<layers::AsyncCanvasRenderer> mRenderer;
uint32_t mWidth;
uint32_t mHeight;
layers::LayersBackend mCompositorBackendType;
@ -58,7 +58,7 @@ class OffscreenCanvas final : public DOMEventTargetHelper,
OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth, uint32_t aHeight,
layers::LayersBackend aCompositorBackend,
layers::CanvasRenderer* aRenderer);
layers::AsyncCanvasRenderer* aRenderer);
nsCOMPtr<nsIGlobalObject> GetParentObject() const { return GetOwnerGlobal(); }
@ -170,7 +170,7 @@ class OffscreenCanvas final : public DOMEventTargetHelper,
layers::LayersBackend mCompositorBackendType;
RefPtr<layers::CanvasClient> mCanvasClient;
RefPtr<layers::CanvasRenderer> mCanvasRenderer;
RefPtr<layers::AsyncCanvasRenderer> mCanvasRenderer;
};
} // namespace dom

Просмотреть файл

@ -202,6 +202,9 @@ void WebGLContext::DestroyResourcesAndContext() {
mDefaultVertexArray = nullptr;
mBoundTransformFeedback = nullptr;
mDefaultTransformFeedback = nullptr;
#if defined(MOZ_WIDGET_ANDROID)
mVRScreen = nullptr;
#endif
mQuerySlot_SamplesPassed = nullptr;
mQuerySlot_TFPrimsWritten = nullptr;
@ -247,16 +250,16 @@ void WebGLContext::DestroyResourcesAndContext() {
MOZ_ASSERT(!gl);
}
void ClientWebGLContext::MarkCanvasDirty() {
void ClientWebGLContext::Invalidate() {
if (!mCanvasElement) return;
mCapturedFrameInvalidated = true;
if (mIsCanvasDirty) return;
mIsCanvasDirty = true;
if (mInvalidated) return;
SVGObserverUtils::InvalidateDirectRenderingObservers(mCanvasElement);
mInvalidated = true;
mCanvasElement->InvalidateCanvasContent(nullptr);
}
@ -394,6 +397,19 @@ bool WebGLContext::CreateAndInitGL(
// --
const auto surfaceCaps = [&]() {
auto ret = gl::SurfaceCaps::ForRGBA();
ret.premultAlpha = mOptions.premultipliedAlpha;
ret.preserve = mOptions.preserveDrawingBuffer;
if (!mOptions.alpha) {
ret.premultAlpha = true;
}
return ret;
}();
// --
const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL");
#ifdef XP_WIN
@ -431,11 +447,14 @@ bool WebGLContext::CreateAndInitGL(
// --
typedef decltype(gl::GLContextProviderEGL::CreateHeadless) fnCreateT;
const auto fnCreate = [&](fnCreateT* const pfnCreate,
typedef decltype(
gl::GLContextProviderEGL::CreateOffscreen) fnCreateOffscreenT;
const auto fnCreate = [&](fnCreateOffscreenT* const pfnCreateOffscreen,
const char* const info) {
const gfx::IntSize dummySize(1, 1);
nsCString failureId;
const RefPtr<gl::GLContext> gl = pfnCreate({flags}, &failureId);
const RefPtr<gl::GLContext> gl =
pfnCreateOffscreen(dummySize, surfaceCaps, flags, &failureId);
if (!gl) {
out_failReasons->push_back(WebGLContext::FailureReason(failureId, info));
}
@ -445,15 +464,18 @@ bool WebGLContext::CreateAndInitGL(
const auto newGL = [&]() -> RefPtr<gl::GLContext> {
if (tryNativeGL) {
if (useEGL)
return fnCreate(&gl::GLContextProviderEGL::CreateHeadless, "useEGL");
return fnCreate(&gl::GLContextProviderEGL::CreateOffscreen, "useEGL");
const auto ret =
fnCreate(&gl::GLContextProvider::CreateHeadless, "tryNativeGL");
fnCreate(&gl::GLContextProvider::CreateOffscreen, "tryNativeGL");
if (ret) return ret;
}
if (tryANGLE) {
return fnCreate(&gl::GLContextProviderEGL::CreateHeadless, "tryANGLE");
// Force enable alpha channel to make sure ANGLE use correct framebuffer
// format
MOZ_ASSERT(surfaceCaps.alpha);
return fnCreate(&gl::GLContextProviderEGL::CreateOffscreen, "tryANGLE");
}
return nullptr;
}();
@ -545,6 +567,18 @@ void WebGLContext::Resize(uvec2 requestedSize) {
requestedSize.y = 1;
}
// WebGL 1 spec:
// WebGL presents its drawing buffer to the HTML page compositor immediately
// before a compositing operation, but only if at least one of the following
// has occurred since the previous compositing operation:
//
// * Context creation
// * Canvas resize
// * clear, drawArrays, or drawElements has been called while the drawing
// buffer is the currently bound framebuffer
mShouldPresent = true;
if (requestedSize == mRequestedSize) return;
// Kill our current default fb(s), for later lazy allocation.
mRequestedSize = requestedSize;
mDefaultFB = nullptr;
@ -848,8 +882,6 @@ void WebGLContext::OnEndOfFrame() {
mDataAllocGLCallCount = 0;
gl->ResetSyncCallCount("WebGLContext PresentScreenBuffer");
mDrawCallsSinceLastFlush = 0;
BumpLru();
}
@ -888,6 +920,53 @@ void WebGLContext::BlitBackbufferToCurDriverFB(
}
}
// TODO: (JG) I think this should be removed, the Client should manage
// TextureClients, and imperitively tell the Host what to render to.
Maybe<ICRData> WebGLContext::InitializeCanvasRenderer(
layers::LayersBackend backend) {
if (!gl) {
return Nothing();
}
ICRData ret;
ret.size = {DrawingBufferSize().x, DrawingBufferSize().y};
ret.hasAlpha = mOptions.alpha;
ret.isPremultAlpha = IsPremultAlpha();
auto flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
if ((!IsPremultAlpha()) && mOptions.alpha) {
flags |= layers::TextureFlags::NON_PREMULTIPLIED;
}
// NB: This is weak. Creating TextureClient objects in the host-side
// WebGLContext class... but these are different concepts of host/client.
// Host/ClientWebGLContext represent cross-process communication but
// TextureHost/Client represent synchronous texture access, which can
// be uniprocess and, for us, is. Also note that TextureClient couldn't
// be in the content process like ClientWebGLContext since TextureClient
// uses a GL context.
UniquePtr<gl::SurfaceFactory> factory = gl::GLScreenBuffer::CreateFactory(
gl, gl->Caps(), nullptr, backend, gl->IsANGLE(), flags);
mBackend = backend;
if (!factory) {
// Absolutely must have a factory here, so create a basic one
factory = MakeUnique<gl::SurfaceFactory_Basic>(gl, gl->Caps(), flags);
mBackend = layers::LayersBackend::LAYERS_BASIC;
}
gl->Screen()->Morph(std::move(factory));
#if defined(MOZ_WIDGET_ANDROID)
// On Android we are using a different GLScreenBuffer for WebVR, so we need
// a resize here because PresentScreenBuffer() may not be called for the
// gl->Screen() after we set the new factory.
mForceResizeOnPresent = true;
#endif
mVRReady = true;
return Some(ret);
}
// -
template <typename T, typename... Args>
@ -899,205 +978,105 @@ constexpr auto MakeArray(Args... args) -> std::array<T, sizeof...(Args)> {
// For an overview of how WebGL compositing works, see:
// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
bool WebGLContext::PresentInto(gl::SwapChain& swapChain) {
OnEndOfFrame();
bool WebGLContext::PresentScreenBuffer(gl::GLScreenBuffer* const targetScreen) {
const FuncScope funcScope(*this, "<PresentScreenBuffer>");
if (IsContextLost()) return false;
mDrawCallsSinceLastFlush = 0;
if (!mShouldPresent) return false;
if (!ValidateAndInitFB(nullptr)) return false;
{
auto presenter = swapChain.Acquire(mDefaultFB->mSize);
if (!presenter) {
GenerateWarning("Swap chain surface creation failed.");
LoseContext();
return false;
}
const auto& screen = targetScreen ? targetScreen : gl->Screen();
bool needsResize = mForceResizeOnPresent;
needsResize |=
!screen->IsReadBufferReady() || (screen->Size() != mDefaultFB->mSize);
if (needsResize && !screen->Resize(mDefaultFB->mSize)) {
GenerateWarning("screen->Resize failed. Losing context.");
LoseContext();
return false;
}
mForceResizeOnPresent = false;
const auto destFb = presenter->Fb();
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
BlitBackbufferToCurDriverFB();
if (!mOptions.preserveDrawingBuffer) {
if (gl->IsSupported(gl::GLFeature::invalidate_framebuffer)) {
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, mDefaultFB->mFB);
constexpr auto attachments = MakeArray<GLenum>(
LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
gl->fInvalidateFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
attachments.size(), attachments.data());
}
mDefaultFB_IsInvalid = true;
}
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
BlitBackbufferToCurDriverFB();
#ifdef DEBUG
if (!mOptions.alpha) {
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
uint32_t pixel = 0xffbadbad;
gl->fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
&pixel);
MOZ_ASSERT((pixel & 0xff000000) == 0xff000000);
}
#endif
if (!mOptions.alpha) {
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
uint32_t pixel = 3;
gl->fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, &pixel);
MOZ_ASSERT((pixel & 0xff000000) == 0xff000000);
}
#endif
return true;
}
bool WebGLContext::PresentIntoXR(gl::SwapChain& swapChain,
const gl::MozFramebuffer& fb) {
OnEndOfFrame();
auto presenter = swapChain.Acquire(fb.mSize);
if (!presenter) {
GenerateWarning("Swap chain surface creation failed.");
if (!screen->PublishFrame(screen->Size())) {
GenerateWarning("PublishFrame failed. Losing context.");
LoseContext();
return false;
}
const auto destFb = presenter->Fb();
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
BlitBackbufferToCurDriverFB(&fb);
// https://immersive-web.github.io/webxr/#opaque-framebuffer
// Opaque framebuffers will always be cleared regardless of the
// associated WebGL contexts preserveDrawingBuffer value.
if (gl->IsSupported(gl::GLFeature::invalidate_framebuffer)) {
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fb.mFB);
constexpr auto attachments = MakeArray<GLenum>(
LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
gl->fInvalidateFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, attachments.size(),
attachments.data());
if (!mOptions.preserveDrawingBuffer) {
if (gl->IsSupported(gl::GLFeature::invalidate_framebuffer)) {
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mDefaultFB->mFB);
constexpr auto attachments = MakeArray<GLenum>(
LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
gl->fInvalidateFramebuffer(LOCAL_GL_FRAMEBUFFER, attachments.size(),
attachments.data());
}
mDefaultFB_IsInvalid = true;
}
mResolvedDefaultFB = nullptr;
mShouldPresent = false;
OnEndOfFrame();
return true;
}
void WebGLContext::Present(WebGLFramebuffer* const fb,
const layers::TextureType consumerType) {
const FuncScope funcScope(*this, "<Present>");
if (IsContextLost()) return;
auto swapChain = &mSwapChain;
const gl::MozFramebuffer* maybeFB = nullptr;
if (fb) {
swapChain = &fb->mOpaqueSwapChain;
maybeFB = fb->mOpaque.get();
} else {
mResolvedDefaultFB = nullptr;
bool WebGLContext::PresentScreenBufferVR(
gl::GLScreenBuffer* const aTargetScreen,
const gl::MozFramebuffer* const fb) {
const FuncScope funcScope(*this, "<PresentScreenBufferVR>");
if (IsContextLost()) {
return false;
}
if (!swapChain->mFactory) {
auto typedFactory = gl::SurfaceFactory::Create(gl, consumerType);
if (typedFactory) {
swapChain->mFactory = std::move(typedFactory);
}
if (!fb) {
// WebVR fallback
return PresentScreenBuffer(aTargetScreen);
}
if (!swapChain->mFactory) {
NS_WARNING("Failed to make an ideal SurfaceFactory.");
swapChain->mFactory = MakeUnique<gl::SurfaceFactory_Basic>(*gl);
}
MOZ_ASSERT(swapChain->mFactory);
if (maybeFB) {
(void)PresentIntoXR(*swapChain, *maybeFB);
} else {
(void)PresentInto(*swapChain);
mDrawCallsSinceLastFlush = 0;
const auto& screen = aTargetScreen ? aTargetScreen : gl->Screen();
bool needsResize = mForceResizeOnPresent;
needsResize |= !screen->IsReadBufferReady() || (screen->Size() != fb->mSize);
if (needsResize && !screen->Resize(fb->mSize)) {
GenerateWarning("screen->Resize failed. Losing context.");
LoseContext();
return false;
}
mForceResizeOnPresent = false;
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
BlitBackbufferToCurDriverFB(fb);
if (!screen->PublishFrame(screen->Size())) {
GenerateWarning("PublishFrame failed. Losing context.");
LoseContext();
return false;
}
mResolvedDefaultFB = nullptr;
OnEndOfFrame();
return true;
}
Maybe<layers::SurfaceDescriptor> WebGLContext::GetFrontBuffer(
WebGLFramebuffer* const fb, const layers::TextureType consumerType) {
auto swapChain = &mSwapChain;
if (fb) {
swapChain = &fb->mOpaqueSwapChain;
}
if (swapChain->mFactory &&
swapChain->mFactory->mDesc.consumerType != consumerType) {
swapChain->mFactory = nullptr; // Better luck next Present.
}
const auto& front = swapChain->FrontBuffer();
if (!front) return {};
return front->ToSurfaceDescriptor();
}
RefPtr<gfx::DataSourceSurface> WebGLContext::GetFrontBufferSnapshot() {
const auto& front = mSwapChain.FrontBuffer();
if (!front) return nullptr;
// -
front->LockProd();
front->ProducerReadAcquire();
auto reset = MakeScopeExit([&] {
front->ProducerReadRelease();
front->UnlockProd();
});
// -
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1);
if (IsWebGL2()) {
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, 0);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
}
// -
const auto readFbWas = mBoundReadFramebuffer;
const auto pboWas = mBoundPixelPackBuffer;
GLenum fbTarget = LOCAL_GL_READ_FRAMEBUFFER;
if (!IsWebGL2()) {
fbTarget = LOCAL_GL_FRAMEBUFFER;
}
gl->fBindFramebuffer(fbTarget, front->mFb ? front->mFb->mFB : 0);
if (pboWas) {
BindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, nullptr);
}
auto reset2 = MakeScopeExit([&] {
DoBindFB(readFbWas, fbTarget);
if (pboWas) {
BindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, pboWas);
}
});
const auto& size = front->mDesc.size;
const auto surfFormat = mOptions.alpha ? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
const auto stride = size.width * 4;
RefPtr<gfx::DataSourceSurface> surf =
gfx::Factory::CreateDataSourceSurfaceWithStride(size, surfFormat, stride,
/*zero=*/true);
MOZ_ASSERT(surf);
if (NS_WARN_IF(!surf)) return nullptr;
// -
{
const gfx::DataSourceSurface::ScopedMap map(
surf, gfx::DataSourceSurface::READ_WRITE);
if (!map.IsMapped()) {
MOZ_ASSERT(false);
return nullptr;
}
MOZ_ASSERT(map.GetStride() == stride);
gl->fReadPixels(0, 0, size.width, size.height, LOCAL_GL_RGBA,
LOCAL_GL_UNSIGNED_BYTE, map.GetData());
gfxUtils::ConvertBGRAtoRGBA(map.GetData(), stride * size.height);
}
return surf;
}
// ------------------------
RefPtr<gfx::DataSourceSurface> GetTempSurface(const gfx::IntSize& aSize,
gfx::SurfaceFormat& aFormat) {
uint32_t stride =
@ -1106,6 +1085,90 @@ RefPtr<gfx::DataSourceSurface> GetTempSurface(const gfx::IntSize& aSize,
stride);
}
void WriteFrontToFile(gl::GLContext* gl, gl::GLScreenBuffer* screen,
const char* fname, bool needsPremult) {
auto frontbuffer = screen->Front()->Surf();
const auto& readSize = frontbuffer->mSize;
auto format = frontbuffer->mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
RefPtr<gfx::DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
if (NS_WARN_IF(!resultSurf)) {
MOZ_ASSERT_UNREACHABLE("FAIL");
return;
}
if (!gl->Readback(frontbuffer, resultSurf)) {
NS_WARNING("Failed to read back canvas surface.");
MOZ_ASSERT_UNREACHABLE("FAIL");
return;
}
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
}
MOZ_ASSERT(resultSurf);
gfxUtils::WriteAsPNG(resultSurf, fname);
}
bool WebGLContext::Present() {
if (!PresentScreenBuffer()) {
return false;
}
if (XRE_IsContentProcess()) {
// That's all!
return true;
}
// Set the CompositableHost to use the front buffer as the display,
auto flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
if ((!IsPremultAlpha()) && mOptions.alpha) {
flags |= layers::TextureFlags::NON_PREMULTIPLIED;
}
const auto& screen = gl->Screen();
if (!screen->Front()->Surf()) {
GenerateWarning(
"Present failed due to missing front buffer. Losing context.");
LoseContext();
return false;
}
if (mBackend == layers::LayersBackend::LAYERS_NONE) {
GenerateWarning(
"Present was not given a valid compositor layer type. Losing context.");
LoseContext();
return false;
}
// TODO: I probably need to hold onto screen->Front()->Surf() somehow
layers::SurfaceDescriptor surfaceDescriptor;
screen->Front()->Surf()->ToSurfaceDescriptor(&surfaceDescriptor);
if (!mCompositableHost) {
return false;
}
wr::MaybeExternalImageId noExternalImageId = Nothing();
RefPtr<layers::TextureHost> host = layers::TextureHost::Create(
surfaceDescriptor, null_t(), nullptr, mBackend, flags, noExternalImageId);
if (!host) {
GenerateWarning("Present failed to create TextuteHost. Losing context.");
LoseContext();
return false;
}
AutoTArray<layers::CompositableHost::TimedTexture, 1> textures;
const auto t = textures.AppendElement();
t->mTexture = host;
t->mTimeStamp = TimeStamp::Now();
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), nsIntSize(host->GetSize()));
t->mFrameID = 0;
t->mProducerID = 0;
mCompositableHost->UseTextureHost(textures);
return true;
}
void WebGLContext::DummyReadFramebufferOperation() {
if (!mBoundReadFramebuffer) return; // Infallible.
@ -1577,6 +1640,119 @@ CheckedUint32 WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width,
return totalBytes;
}
void WebGLContext::ClearVRFrame() {
#if defined(MOZ_WIDGET_ANDROID)
mVRScreen = nullptr;
#endif
}
RefPtr<layers::SharedSurfaceTextureClient> WebGLContext::GetVRFrame(
WebGLFramebuffer* fb) {
if (!gl) return nullptr;
EnsureVRReady();
const gl::MozFramebuffer* maybeFB = nullptr;
if (fb) {
maybeFB = fb->mOpaque.get();
MOZ_ASSERT(maybeFB);
}
UniquePtr<gl::GLScreenBuffer>* maybeVrScreen = nullptr;
#if defined(MOZ_WIDGET_ANDROID)
maybeVrScreen = &mVRScreen;
#endif
RefPtr<layers::SharedSurfaceTextureClient> sharedSurface;
if (maybeVrScreen) {
auto& vrScreen = *maybeVrScreen;
// Create a custom GLScreenBuffer for VR.
if (!vrScreen) {
auto caps = gl->Screen()->mCaps;
vrScreen = gl::GLScreenBuffer::Create(gl, gfx::IntSize(1, 1), caps);
RefPtr<layers::ImageBridgeChild> imageBridge =
layers::ImageBridgeChild::GetSingleton();
if (imageBridge) {
layers::TextureFlags flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
UniquePtr<gl::SurfaceFactory> factory =
gl::GLScreenBuffer::CreateFactory(gl, caps, imageBridge.get(),
flags);
vrScreen->Morph(std::move(factory));
}
}
MOZ_ASSERT(vrScreen);
// Swap buffers as though composition has occurred.
// We will then share the resulting front buffer to be submitted to the VR
// compositor.
PresentScreenBufferVR(vrScreen.get(), maybeFB);
if (IsContextLost()) return nullptr;
sharedSurface = vrScreen->Front();
if (!sharedSurface || !sharedSurface->Surf() ||
!sharedSurface->Surf()->IsBufferAvailable())
return nullptr;
// Make sure that the WebGL buffer is committed to the attached
// SurfaceTexture on Android.
sharedSurface->Surf()->ProducerAcquire();
sharedSurface->Surf()->Commit();
sharedSurface->Surf()->ProducerRelease();
} else {
/**
* Swap buffers as though composition has occurred.
* We will then share the resulting front buffer to be submitted to the VR
* compositor.
*/
PresentScreenBufferVR(nullptr, maybeFB);
gl::GLScreenBuffer* screen = gl->Screen();
if (!screen) return nullptr;
sharedSurface = screen->Front();
if (!sharedSurface) return nullptr;
}
return sharedSurface;
}
void WebGLContext::EnsureVRReady() {
if (mVRReady) {
return;
}
// Make not composited canvases work with WebVR. See bug #1492554
// WebGLContext::InitializeCanvasRenderer is only called when the 2D
// compositor renders a WebGL canvas for the first time. This causes canvases
// not added to the DOM not to work properly with WebVR. Here we mimic what
// InitializeCanvasRenderer does internally as a workaround.
const auto caps = gl->Screen()->mCaps;
auto flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
if (!IsPremultAlpha() && mOptions.alpha) {
flags |= layers::TextureFlags::NON_PREMULTIPLIED;
}
RefPtr<layers::ImageBridgeChild> imageBridge =
layers::ImageBridgeChild::GetSingleton();
if (!imageBridge) {
return;
}
auto factory =
gl::GLScreenBuffer::CreateFactory(gl, caps, imageBridge.get(), flags);
gl->Screen()->Morph(std::move(factory));
bool needsResize = false;
#if defined(MOZ_WIDGET_ANDROID)
// On Android we are using a different GLScreenBuffer for WebVR, so we need
// a resize here because PresentScreenBuffer() may not be called for the
// gl->Screen() after we set the new factory.
needsResize = true;
#endif
if (needsResize) {
const auto& size = DrawingBufferSize();
gl->Screen()->Resize({size.x, size.y});
}
mVRReady = true;
}
////////////////////////////////////////////////////////////////////////////////
const char* WebGLContext::FuncName() const {

Просмотреть файл

@ -11,7 +11,6 @@
#include "GLContextTypes.h"
#include "GLDefs.h"
#include "GLScreenBuffer.h"
#include "mozilla/Attributes.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/BindingDeclarations.h"
@ -100,8 +99,7 @@ class MozFramebuffer;
namespace layers {
class CompositableHost;
class SurfaceDescriptor;
} // namespace layers
}
namespace webgl {
class AvailabilityRunnable;
@ -270,7 +268,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
~LruPosition() { reset(); }
};
mutable LruPosition mLruPosition;
LruPosition mLruPosition;
public:
void BumpLru() {
@ -480,16 +478,13 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
return mOptions.preserveDrawingBuffer;
}
// Present to compositor
private:
bool PresentInto(gl::SwapChain& swapChain);
bool PresentIntoXR(gl::SwapChain& swapChain, const gl::MozFramebuffer& fb);
// Prepare the context for capture before compositing
bool PresentScreenBuffer(gl::GLScreenBuffer* const screen = nullptr);
bool PresentScreenBufferVR(gl::GLScreenBuffer* const screen = nullptr,
const gl::MozFramebuffer* const fb = nullptr);
public:
void Present(WebGLFramebuffer*, layers::TextureType);
RefPtr<gfx::DataSourceSurface> GetFrontBufferSnapshot();
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(WebGLFramebuffer*,
layers::TextureType);
// Present to compositor
bool Present();
void RunContextLossTimer();
void CheckForContextLoss();
@ -589,6 +584,10 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
void PixelStorei(GLenum pname, uint32_t param);
void PolygonOffset(GLfloat factor, GLfloat units);
RefPtr<layers::SharedSurfaceTextureClient> GetVRFrame(WebGLFramebuffer* fb);
void ClearVRFrame();
void EnsureVRReady();
////
webgl::PackingInfo ValidImplementationColorReadPI(
@ -1179,7 +1178,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
// Used for some hardware (particularly Tegra 2 and 4) that likes to
// be Flushed while doing hundreds of draw calls.
mutable uint64_t mDrawCallsSinceLastFlush = 0;
int mDrawCallsSinceLastFlush = 0;
mutable uint64_t mWarningCount = 0;
const uint64_t mMaxWarnings;
@ -1203,6 +1202,9 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
bool mNeedsIndexValidation = false;
const bool mAllowFBInvalidation;
#if defined(MOZ_WIDGET_ANDROID)
UniquePtr<gl::GLScreenBuffer> mVRScreen;
#endif
bool Has64BitTimestamps() const;
@ -1214,8 +1216,6 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
mutable bool mDefaultFB_IsInvalid = false;
mutable UniquePtr<gl::MozFramebuffer> mResolvedDefaultFB;
gl::SwapChain mSwapChain;
// --
bool EnsureDefaultFB();

Просмотреть файл

@ -38,9 +38,6 @@ static bool ShouldDeferAttachment(const WebGLContext* const webgl,
}
}
WebGLFBAttachPoint::WebGLFBAttachPoint() = default;
WebGLFBAttachPoint::WebGLFBAttachPoint(WebGLFBAttachPoint&) = default;
WebGLFBAttachPoint::WebGLFBAttachPoint(const WebGLContext* const webgl,
const GLenum attachmentPoint)
: mAttachmentPoint(attachmentPoint),

Просмотреть файл

@ -10,8 +10,8 @@
#include "mozilla/WeakPtr.h"
#include "GLScreenBuffer.h"
#include "WebGLObjectModel.h"
#include "WebGLRenderbuffer.h"
#include "WebGLStrongTypes.h"
#include "WebGLTexture.h"
#include "WebGLTypes.h"
@ -58,10 +58,11 @@ class WebGLFBAttachPoint final {
////
WebGLFBAttachPoint();
explicit WebGLFBAttachPoint(WebGLFBAttachPoint&); // Make this private.
WebGLFBAttachPoint() = default;
WebGLFBAttachPoint(const WebGLContext* webgl, GLenum attachmentPoint);
explicit WebGLFBAttachPoint(WebGLFBAttachPoint&) =
default; // Make this private.
public:
~WebGLFBAttachPoint();
@ -139,7 +140,6 @@ class WebGLFramebuffer final : public WebGLContextBoundObject,
const GLuint mGLName;
bool mHasBeenBound = false;
const UniquePtr<gl::MozFramebuffer> mOpaque;
gl::SwapChain mOpaqueSwapChain;
bool mInOpaqueRAF = false;
private:

Просмотреть файл

@ -59,19 +59,22 @@ DEFINE_ASYNC(HostWebGLContext::DeleteTexture)
DEFINE_ASYNC(HostWebGLContext::DeleteTransformFeedback)
DEFINE_ASYNC(HostWebGLContext::DeleteVertexArray)
DEFINE_ASYNC(HostWebGLContext::ClearVRFrame)
// DEFINE_SYNC(HostWebGLContext::GetVRFrame)
DEFINE_ASYNC(HostWebGLContext::Disable)
DEFINE_ASYNC(HostWebGLContext::Enable)
DEFINE_ASYNC(HostWebGLContext::GenerateError)
DEFINE_SYNC(HostWebGLContext::GetCompileResult)
DEFINE_SYNC(HostWebGLContext::GetFrontBufferSnapshot)
DEFINE_SYNC(HostWebGLContext::GetFragDataLocation)
DEFINE_SYNC(HostWebGLContext::GetFrontBuffer)
DEFINE_SYNC(HostWebGLContext::GetLinkResult)
// DEFINE_SYNC(HostWebGLContext::GetLinkResult)
DEFINE_SYNC(HostWebGLContext::InitializeCanvasRenderer)
DEFINE_SYNC(HostWebGLContext::IsEnabled)
DEFINE_ASYNC(HostWebGLContext::Resize)
DEFINE_ASYNC(HostWebGLContext::RequestExtension)
DEFINE_SYNC(HostWebGLContext::DrawingBufferSize)
DEFINE_SYNC(HostWebGLContext::OnMemoryPressure)
DEFINE_SYNC(HostWebGLContext::Present)
DEFINE_ASYNC(HostWebGLContext::DidRefresh)
DEFINE_SYNC(HostWebGLContext::GetParameter)
DEFINE_SYNC(HostWebGLContext::GetString)
@ -108,7 +111,6 @@ DEFINE_ASYNC(HostWebGLContext::LineWidth)
DEFINE_ASYNC(HostWebGLContext::LinkProgram)
DEFINE_SYNC(HostWebGLContext::PixelStorei)
DEFINE_ASYNC(HostWebGLContext::PolygonOffset)
DEFINE_ASYNC(HostWebGLContext::Present)
DEFINE_ASYNC(HostWebGLContext::SampleCoverage)
DEFINE_ASYNC(HostWebGLContext::Scissor)
DEFINE_ASYNC(HostWebGLContext::ShaderSource)

Просмотреть файл

@ -136,5 +136,15 @@ mozilla::ipc::IPCResult WebGLParent::RecvUpdateCompositableHandle(
return IPC_OK();
}
RefPtr<layers::SharedSurfaceTextureClient> WebGLParent::GetVRFrame(
webgl::ObjectId id) {
if (!mHost) {
return nullptr;
}
return mHost->GetVRFrame(id);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -37,10 +37,13 @@ class WebGLParent : public PWebGLParent,
const webgl::InitContextDesc&, UniquePtr<HostWebGLCommandSinkP>&& aSinkP,
UniquePtr<HostWebGLCommandSinkI>&& aSinkI, webgl::InitContextResult* out);
RefPtr<layers::SharedSurfaceTextureClient> GetVRFrame(webgl::ObjectId);
// Drain the command queue now. Used by synchronous IpdlQueue consumers.
bool RunQueue(uint64_t) { return RunCommandQueue(); }
WebGLParent(); // For IPDL
// For IPDL:
WebGLParent();
private:
~WebGLParent();

Просмотреть файл

@ -989,8 +989,6 @@ inline std::string ToString(const nsACString& text) {
return {text.BeginReading(), text.Length()};
}
// -
} // namespace mozilla
#endif

Просмотреть файл

@ -261,6 +261,7 @@ HTMLCanvasElement* XRWebGLLayer::GetCanvas() {
void XRWebGLLayer::SessionEnded() {
DeleteFramebuffer();
mWebGL->ClearVRFrame();
}
} // namespace dom

Просмотреть файл

@ -6,8 +6,6 @@
#ifndef nsICanvasRenderingContextInternal_h___
#define nsICanvasRenderingContextInternal_h___
#include <memory>
#include "mozilla/gfx/2D.h"
#include "nsISupports.h"
#include "nsIInputStream.h"
@ -31,7 +29,6 @@ class nsDisplayListBuilder;
class nsIDocShell;
namespace mozilla {
class ClientWebGLContext;
class PresShell;
namespace layers {
class CanvasLayer;
@ -40,7 +37,6 @@ class CompositableHandle;
class Layer;
class LayerManager;
class LayerTransactionChild;
class PersistentBufferProvider;
class WebRenderCanvasData;
} // namespace layers
namespace gfx {
@ -61,10 +57,6 @@ class nsICanvasRenderingContextInternal : public nsISupports,
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
nsICanvasRenderingContextInternal()
: mSharedPtrPtr(
std::make_shared<nsICanvasRenderingContextInternal*>(this)) {}
void SetCanvasElement(mozilla::dom::HTMLCanvasElement* parentCanvas) {
RemovePostRefreshObserver();
mCanvasElement = parentCanvas;
@ -137,10 +129,6 @@ class nsICanvasRenderingContextInternal : public nsISupports,
virtual already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
gfxAlphaType* out_alphaType = nullptr) = 0;
virtual RefPtr<mozilla::gfx::SourceSurface> GetFrontBufferSnapshot(bool) {
return GetSurfaceSnapshot();
}
// If this is called with true, the backing store of the canvas should
// be created as opaque; all compositing operators should assume the
// dst alpha is always 1.0. If this is never called, the context's
@ -214,13 +202,6 @@ class nsICanvasRenderingContextInternal : public nsISupports,
return false;
}
virtual void OnBeforePaintTransaction() {}
virtual void OnDidPaintTransaction() {}
virtual mozilla::layers::PersistentBufferProvider* GetBufferProvider() {
return nullptr;
}
virtual mozilla::ClientWebGLContext* AsWebgl() { return nullptr; }
//
// shmem support
//
@ -235,9 +216,6 @@ class nsICanvasRenderingContextInternal : public nsISupports,
RefPtr<mozilla::dom::HTMLCanvasElement> mCanvasElement;
RefPtr<mozilla::dom::OffscreenCanvas> mOffscreenCanvas;
RefPtr<nsRefreshDriver> mRefreshDriver;
public:
const std::shared_ptr<nsICanvasRenderingContextInternal* const> mSharedPtrPtr;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,

Просмотреть файл

@ -27,7 +27,8 @@
#include "mozilla/dom/OffscreenCanvas.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/layers/CanvasRenderer.h"
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/OOPCanvasRenderer.h"
#include "mozilla/layers/WebRenderCanvasRenderer.h"
#include "mozilla/layers/WebRenderUserData.h"
#include "mozilla/MouseEvents.h"
@ -381,6 +382,10 @@ HTMLCanvasElement::~HTMLCanvasElement() {
if (mRequestedFrameRefreshObserver) {
mRequestedFrameRefreshObserver->DetachFromRefreshDriver();
}
if (mAsyncCanvasRenderer) {
mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr;
}
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
@ -726,7 +731,8 @@ nsresult HTMLCanvasElement::ExtractData(JSContext* aCx,
bool usePlaceholder = !CanvasUtils::IsImageExtractionAllowed(
OwnerDoc(), aCx, aSubjectPrincipal);
return ImageEncoder::ExtractData(aType, aOptions, GetSize(), usePlaceholder,
mCurrentContext, mCanvasRenderer, aStream);
mCurrentContext, mAsyncCanvasRenderer,
aStream);
}
nsresult HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
@ -825,7 +831,10 @@ OffscreenCanvas* HTMLCanvasElement::TransferControlToOffscreen(
}
if (!mOffscreenCanvas) {
MOZ_CRASH("todo");
nsIntSize sz = GetWidthHeight();
RefPtr<AsyncCanvasRenderer> renderer = GetAsyncCanvasRenderer();
renderer->SetWidth(sz.width);
renderer->SetHeight(sz.height);
nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow();
if (!win) {
@ -833,10 +842,9 @@ OffscreenCanvas* HTMLCanvasElement::TransferControlToOffscreen(
return nullptr;
}
// nsIntSize sz = GetWidthHeight();
// mOffscreenCanvas =
// new OffscreenCanvas(win->AsGlobal(), sz.width, sz.height,
// GetCompositorBackendType(), renderer);
mOffscreenCanvas =
new OffscreenCanvas(win->AsGlobal(), sz.width, sz.height,
GetCompositorBackendType(), renderer);
if (mWriteOnly) {
mOffscreenCanvas->SetWriteOnly();
}
@ -1095,17 +1103,80 @@ bool HTMLCanvasElement::GetOpaqueAttr() {
}
CanvasContextType HTMLCanvasElement::GetCurrentContextType() {
if (mAsyncCanvasRenderer) {
return mAsyncCanvasRenderer->GetContextType();
}
return mCurrentContextType;
}
already_AddRefed<Layer> HTMLCanvasElement::GetCanvasLayer(
nsDisplayListBuilder* aBuilder, Layer* aOldLayer, LayerManager* aManager) {
// The address of sOffscreenCanvasLayerUserDataDummy is used as the user
// data key for retained LayerManagers managed by FrameLayerBuilder.
// We don't much care about what value in it, so just assign a dummy
// value for it.
static uint8_t sOffscreenCanvasLayerUserDataDummy = 0;
static uint8_t sOffscreenImageLayerUserDataDummy = 0;
if (mCurrentContext) {
return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
}
if (mOffscreenCanvas) {
MOZ_CRASH("todo");
CanvasContextType contentType = mAsyncCanvasRenderer->GetContextType();
if (contentType == CanvasContextType::NoContext) {
// context is not created yet.
return nullptr;
}
if (contentType != CanvasContextType::ImageBitmap) {
if (!mResetLayer && aOldLayer &&
aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) {
RefPtr<Layer> ret = aOldLayer;
return ret.forget();
}
RefPtr<CanvasLayer> layer = aManager->CreateCanvasLayer();
if (!layer) {
NS_WARNING("CreateCanvasLayer failed!");
return nullptr;
}
LayerUserData* userData = nullptr;
layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
CanvasRenderer* canvasRenderer = layer->CreateOrGetCanvasRenderer();
if (!InitializeCanvasRenderer(aBuilder, canvasRenderer)) {
return nullptr;
}
layer->Updated();
mResetLayer = false;
return layer.forget();
}
if (contentType == CanvasContextType::ImageBitmap) {
if (!mResetLayer && aOldLayer &&
aOldLayer->HasUserData(&sOffscreenImageLayerUserDataDummy)) {
RefPtr<Layer> ret = aOldLayer;
return ret.forget();
}
RefPtr<ImageLayer> layer = aManager->CreateImageLayer();
if (!layer) {
NS_WARNING("CreateImageLayer failed!");
return nullptr;
}
LayerUserData* userData = nullptr;
layer->SetUserData(&sOffscreenImageLayerUserDataDummy, userData);
RefPtr<ImageContainer> imageContainer =
mAsyncCanvasRenderer->GetImageContainer();
MOZ_ASSERT(imageContainer);
layer->SetContainer(imageContainer);
mResetLayer = false;
return layer.forget();
}
}
return nullptr;
@ -1117,7 +1188,37 @@ bool HTMLCanvasElement::UpdateWebRenderCanvasData(
return mCurrentContext->UpdateWebRenderCanvasData(aBuilder, aCanvasData);
}
if (mOffscreenCanvas) {
MOZ_CRASH("todo");
CanvasContextType contentType = mAsyncCanvasRenderer->GetContextType();
if (contentType == CanvasContextType::NoContext) {
// context is not created yet.
return false;
}
if (contentType != CanvasContextType::ImageBitmap) {
CanvasRenderer* renderer = aCanvasData->GetCanvasRenderer();
if (!mResetLayer && renderer) {
return true;
}
renderer = aCanvasData->CreateCanvasRenderer();
if (!InitializeCanvasRenderer(aBuilder, renderer)) {
// Clear CanvasRenderer of WebRenderCanvasData
aCanvasData->ClearCanvasRenderer();
return false;
}
MOZ_ASSERT(renderer);
mResetLayer = false;
return true;
}
if (contentType == CanvasContextType::ImageBitmap) {
RefPtr<ImageContainer> imageContainer =
mAsyncCanvasRenderer->GetImageContainer();
MOZ_ASSERT(imageContainer);
aCanvasData->SetImageContainer(imageContainer);
mResetLayer = false;
return true;
}
}
// Clear CanvasRenderer of WebRenderCanvasData
@ -1132,7 +1233,11 @@ bool HTMLCanvasElement::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
}
if (mOffscreenCanvas) {
MOZ_CRASH("todo");
CanvasInitializeData data;
data.mRenderer = GetAsyncCanvasRenderer();
data.mSize = GetWidthHeight();
aRenderer->Initialize(data);
return true;
}
return false;
@ -1258,6 +1363,25 @@ already_AddRefed<SourceSurface> HTMLCanvasElement::GetSurfaceSnapshot(
return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType);
}
AsyncCanvasRenderer* HTMLCanvasElement::GetAsyncCanvasRenderer() {
if (!mAsyncCanvasRenderer) {
mAsyncCanvasRenderer = new AsyncCanvasRenderer();
mAsyncCanvasRenderer->mHTMLCanvasElement = this;
}
return mAsyncCanvasRenderer;
}
layers::OOPCanvasRenderer* HTMLCanvasElement::GetOOPCanvasRenderer() {
if (!mOOPCanvasRenderer) {
const auto context = GetWebGLContext();
MOZ_ASSERT(context);
mOOPCanvasRenderer = new OOPCanvasRenderer(context);
}
return mOOPCanvasRenderer;
}
layers::LayersBackend HTMLCanvasElement::GetCompositorBackendType() const {
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc());
if (docWidget) {
@ -1276,8 +1400,29 @@ void HTMLCanvasElement::OnVisibilityChange() {
}
if (mOffscreenCanvas) {
MOZ_CRASH("todo");
// Dispatch to GetActiveEventTarget.
class Runnable final : public CancelableRunnable {
public:
explicit Runnable(AsyncCanvasRenderer* aRenderer)
: mozilla::CancelableRunnable("Runnable"), mRenderer(aRenderer) {}
NS_IMETHOD Run() override {
if (mRenderer && mRenderer->mContext) {
mRenderer->mContext->OnVisibilityChange();
}
return NS_OK;
}
private:
RefPtr<AsyncCanvasRenderer> mRenderer;
};
RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
nsCOMPtr<nsIEventTarget> activeTarget =
mAsyncCanvasRenderer->GetActiveEventTarget();
if (activeTarget) {
activeTarget->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
}
return;
}
@ -1288,8 +1433,29 @@ void HTMLCanvasElement::OnVisibilityChange() {
void HTMLCanvasElement::OnMemoryPressure() {
if (mOffscreenCanvas) {
MOZ_CRASH("todo");
// Dispatch to GetActiveEventTarget.
class Runnable final : public CancelableRunnable {
public:
explicit Runnable(AsyncCanvasRenderer* aRenderer)
: mozilla::CancelableRunnable("Runnable"), mRenderer(aRenderer) {}
NS_IMETHOD Run() override {
if (mRenderer && mRenderer->mContext) {
mRenderer->mContext->OnMemoryPressure();
}
return NS_OK;
}
private:
RefPtr<AsyncCanvasRenderer> mRenderer;
};
RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
nsCOMPtr<nsIEventTarget> activeTarget =
mAsyncCanvasRenderer->GetActiveEventTarget();
if (activeTarget) {
activeTarget->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
}
return;
}
@ -1304,6 +1470,49 @@ void HTMLCanvasElement::OnDeviceReset() {
}
}
/* static */
void HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(
AsyncCanvasRenderer* aRenderer) {
HTMLCanvasElement* element = aRenderer->mHTMLCanvasElement;
if (!element) {
return;
}
if (element->GetWidthHeight() == aRenderer->GetSize()) {
return;
}
gfx::IntSize asyncCanvasSize = aRenderer->GetSize();
ErrorResult rv;
element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width,
DEFAULT_CANVAS_WIDTH, rv);
if (rv.Failed()) {
NS_WARNING(
"Failed to set width attribute to a canvas element asynchronously.");
}
element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height,
DEFAULT_CANVAS_HEIGHT, rv);
if (rv.Failed()) {
NS_WARNING(
"Failed to set height attribute to a canvas element asynchronously.");
}
element->mResetLayer = true;
}
/* static */
void HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(
AsyncCanvasRenderer* aRenderer) {
HTMLCanvasElement* element = aRenderer->mHTMLCanvasElement;
if (!element) {
return;
}
element->InvalidateCanvasContent(nullptr);
}
ClientWebGLContext* HTMLCanvasElement::GetWebGLContext() {
if (GetCurrentContextType() != CanvasContextType::WebGL1 &&
GetCurrentContextType() != CanvasContextType::WebGL2) {

Просмотреть файл

@ -29,6 +29,7 @@ namespace mozilla {
class ClientWebGLContext;
namespace layers {
class AsyncCanvasRenderer;
class CanvasRenderer;
class CanvasLayer;
class Image;
@ -122,6 +123,7 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
public SupportsWeakPtr<HTMLCanvasElement> {
enum { DEFAULT_CANVAS_WIDTH = 300, DEFAULT_CANVAS_HEIGHT = 150 };
typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer;
typedef layers::CanvasRenderer CanvasRenderer;
typedef layers::CanvasLayer CanvasLayer;
typedef layers::Layer Layer;
@ -330,14 +332,23 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
layers::LayersBackend GetCompositorBackendType() const;
void OnVisibilityChange();
void OnMemoryPressure();
void OnDeviceReset();
static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer* aRenderer);
static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer* aRenderer);
already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
void ClearVRFrame();
bool MaybeModified() const { return mMaybeModified; };
AsyncCanvasRenderer* GetAsyncCanvasRenderer();
layers::OOPCanvasRenderer* GetOOPCanvasRenderer();
protected:
virtual ~HTMLCanvasElement();
@ -381,7 +392,8 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
RefPtr<HTMLCanvasPrintState> mPrintState;
nsTArray<WeakPtr<FrameCaptureListener>> mRequestedFrameListeners;
RefPtr<RequestedFrameRefreshObserver> mRequestedFrameRefreshObserver;
RefPtr<CanvasRenderer> mCanvasRenderer;
RefPtr<AsyncCanvasRenderer> mAsyncCanvasRenderer;
RefPtr<layers::OOPCanvasRenderer> mOOPCanvasRenderer;
RefPtr<OffscreenCanvas> mOffscreenCanvas;
RefPtr<HTMLCanvasElementObserver> mContextObserver;

Просмотреть файл

@ -102,8 +102,9 @@ class SharedGL final {
if (!eglContext) {
return nullptr;
}
RefPtr<GLContextEGL> gl =
new GLContextEGL(egl, {}, eglConfig, EGL_NO_SURFACE, eglContext);
RefPtr<GLContextEGL> gl = new GLContextEGL(
egl, CreateContextFlags::NONE, SurfaceCaps::Any(),
/* offscreen? */ false, eglConfig, EGL_NO_SURFACE, eglContext);
if (!gl->Init()) {
NS_WARNING("Fail to create GL context for native blitter.");
return nullptr;

Просмотреть файл

@ -271,12 +271,14 @@ uint8_t GLContext::ChooseDebugFlags(const CreateContextFlags createFlags) {
return debugFlags;
}
GLContext::GLContext(const GLContextDesc& desc, GLContext* sharedContext,
GLContext::GLContext(CreateContextFlags flags, const SurfaceCaps& caps,
GLContext* sharedContext, bool isOffscreen,
bool useTLSIsCurrent)
: mDesc(desc),
mUseTLSIsCurrent(ShouldUseTLSIsCurrent(useTLSIsCurrent)),
mDebugFlags(ChooseDebugFlags(mDesc.flags)),
: mUseTLSIsCurrent(ShouldUseTLSIsCurrent(useTLSIsCurrent)),
mIsOffscreen(isOffscreen),
mDebugFlags(ChooseDebugFlags(flags)),
mSharedContext(sharedContext),
mCaps(caps),
mWorkAroundDriverBugs(
StaticPrefs::gfx_work_around_driver_bugs_AtStartup()) {
mOwningThreadId = PlatformThread::CurrentId();
@ -919,6 +921,14 @@ bool GLContext::InitImpl() {
// We're ready for final setup.
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
// TODO: Remove SurfaceCaps::any.
if (mCaps.any) {
mCaps.any = false;
mCaps.color = true;
mCaps.alpha = false;
}
MOZ_GL_ASSERT(this, IsCurrent());
if (ShouldSpew() && IsExtensionSupported(KHR_debug)) {
@ -1700,6 +1710,71 @@ bool GLContext::ListHasExtension(const GLubyte* extensions,
return false;
}
GLFormats GLContext::ChooseGLFormats(const SurfaceCaps& caps) const {
GLFormats formats;
// If we're on ES2 hardware and we have an explicit request for 16 bits of
// color or less OR we don't support full 8-bit color, return a 4444 or 565
// format.
bool bpp16 = caps.bpp16;
if (IsGLES()) {
if (!IsExtensionSupported(OES_rgb8_rgba8)) bpp16 = true;
} else {
// RGB565 is uncommon on desktop, requiring ARB_ES2_compatibility.
// Since it's also vanishingly useless there, let's not support it.
bpp16 = false;
}
if (bpp16) {
MOZ_ASSERT(IsGLES());
if (caps.alpha) {
formats.color_texInternalFormat = LOCAL_GL_RGBA;
formats.color_texFormat = LOCAL_GL_RGBA;
formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4;
formats.color_rbFormat = LOCAL_GL_RGBA4;
} else {
formats.color_texInternalFormat = LOCAL_GL_RGB;
formats.color_texFormat = LOCAL_GL_RGB;
formats.color_texType = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
formats.color_rbFormat = LOCAL_GL_RGB565;
}
} else {
formats.color_texType = LOCAL_GL_UNSIGNED_BYTE;
if (caps.alpha) {
formats.color_texInternalFormat =
IsGLES() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
formats.color_texFormat = LOCAL_GL_RGBA;
formats.color_rbFormat = LOCAL_GL_RGBA8;
} else {
formats.color_texInternalFormat = IsGLES() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
formats.color_texFormat = LOCAL_GL_RGB;
formats.color_rbFormat = LOCAL_GL_RGB8;
}
}
// Be clear that these are 0 if unavailable.
formats.depthStencil = 0;
if (IsSupported(GLFeature::packed_depth_stencil)) {
formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
}
formats.depth = 0;
if (IsGLES()) {
if (IsExtensionSupported(OES_depth24)) {
formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
} else {
formats.depth = LOCAL_GL_DEPTH_COMPONENT16;
}
} else {
formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
}
formats.stencil = LOCAL_GL_STENCIL_INDEX8;
return formats;
}
bool GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus) {
MOZ_ASSERT(fb);
@ -1786,7 +1861,7 @@ bool GLContext::AssembleOffscreenFBs(const GLuint colorMSRB,
} else {
drawFB = readFB;
}
MOZ_ASSERT(GetIntAs<GLuint>(LOCAL_GL_FRAMEBUFFER_BINDING) == drawFB);
MOZ_ASSERT(GetFB() == drawFB);
if (depthRB) {
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
@ -1844,6 +1919,7 @@ void GLContext::MarkDestroyed() {
// Null these before they're naturally nulled after dtor, as we want GLContext
// to still be alive in *their* dtors.
mScreen = nullptr;
mBlitHelper = nullptr;
mReadTexImageHelper = nullptr;
@ -2033,6 +2109,54 @@ void GLContext::ReportOutstandingNames() {
#endif /* DEBUG */
void GLContext::GuaranteeResolve() { fFinish(); }
const gfx::IntSize& GLContext::OffscreenSize() const {
MOZ_ASSERT(IsOffscreen());
return mScreen->Size();
}
bool GLContext::CreateScreenBufferImpl(const IntSize& size,
const SurfaceCaps& caps) {
UniquePtr<GLScreenBuffer> newScreen =
GLScreenBuffer::Create(this, size, caps);
if (!newScreen) return false;
if (!newScreen->Resize(size)) {
return false;
}
// This will rebind to 0 (Screen) if needed when
// it falls out of scope.
ScopedBindFramebuffer autoFB(this);
mScreen = std::move(newScreen);
return true;
}
bool GLContext::ResizeScreenBuffer(const IntSize& size) {
if (!IsOffscreenSizeAllowed(size)) return false;
return mScreen->Resize(size);
}
void GLContext::ForceDirtyScreen() {
ScopedBindFramebuffer autoFB(0);
BeforeGLDrawCall();
// no-op; just pretend we did something
AfterGLDrawCall();
}
void GLContext::CleanDirtyScreen() {
ScopedBindFramebuffer autoFB(0);
BeforeGLReadCall();
// no-op; we just want to make sure the Read FBO is updated if it needs to be
AfterGLReadCall();
}
bool GLContext::IsOffscreenSizeAllowed(const IntSize& aSize) const {
int32_t biggerDimension = std::max(aSize.width, aSize.height);
int32_t maxAllowed = std::min(mMaxRenderbufferSize, mMaxTextureSize);
@ -2110,6 +2234,119 @@ void SplitByChar(const nsACString& str, const char delim,
out->push_back(nsCString(substr));
}
bool GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest) {
MOZ_ASSERT(src && dest);
MOZ_ASSERT(dest->GetSize() == src->mSize);
if (!MakeCurrent()) {
return false;
}
SharedSurface* prev = GetLockedSurface();
const bool needsSwap = src != prev;
if (needsSwap) {
if (prev) prev->UnlockProd();
src->LockProd();
}
GLuint tempFB = 0;
GLuint tempTex = 0;
{
ScopedBindFramebuffer autoFB(this);
// We're consuming from the producer side, so which do we use?
// Really, we just want a read-only lock, so ConsumerAcquire is the best
// match.
src->ProducerReadAcquire();
if (src->mAttachType == AttachmentType::Screen) {
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
} else {
fGenFramebuffers(1, &tempFB);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, tempFB);
switch (src->mAttachType) {
case AttachmentType::GLTexture:
fFramebufferTexture2D(
LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
src->ProdTextureTarget(), src->ProdTexture(), 0);
break;
case AttachmentType::GLRenderbuffer:
fFramebufferRenderbuffer(
LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, src->ProdRenderbuffer());
break;
default:
MOZ_CRASH("GFX: bad `src->mAttachType`.");
}
DebugOnly<GLenum> status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
MOZ_GL_ASSERT(this, status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
}
if (src->NeedsIndirectReads()) {
fGenTextures(1, &tempTex);
{
ScopedBindTexture autoTex(this, tempTex);
GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
auto width = src->mSize.width;
auto height = src->mSize.height;
fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width, height, 0);
}
fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_TEXTURE_2D, tempTex, 0);
}
ReadPixelsIntoDataSurface(this, dest);
src->ProducerReadRelease();
}
if (tempFB) fDeleteFramebuffers(1, &tempFB);
if (tempTex) {
fDeleteTextures(1, &tempTex);
}
if (needsSwap) {
src->UnlockProd();
if (prev) prev->LockProd();
}
return true;
}
void GLContext::fBindFramebuffer(GLenum target, GLuint framebuffer) {
if (!mScreen) {
raw_fBindFramebuffer(target, framebuffer);
return;
}
switch (target) {
case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
mScreen->BindDrawFB(framebuffer);
return;
case LOCAL_GL_READ_FRAMEBUFFER_EXT:
mScreen->BindReadFB(framebuffer);
return;
case LOCAL_GL_FRAMEBUFFER:
mScreen->BindFB(framebuffer);
return;
default:
// Nothing we care about, likely an error.
break;
}
raw_fBindFramebuffer(target, framebuffer);
}
void GLContext::fCopyTexImage2D(GLenum target, GLint level,
GLenum internalformat, GLint x, GLint y,
GLsizei width, GLsizei height, GLint border) {
@ -2123,13 +2360,40 @@ void GLContext::fCopyTexImage2D(GLenum target, GLint level,
}
BeforeGLReadCall();
raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height,
border);
bool didCopyTexImage2D = false;
if (mScreen) {
didCopyTexImage2D = mScreen->CopyTexImage2D(target, level, internalformat,
x, y, width, height, border);
}
if (!didCopyTexImage2D) {
raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height,
border);
}
AfterGLReadCall();
}
void GLContext::fGetIntegerv(GLenum pname, GLint* params) const {
void GLContext::fGetIntegerv(GLenum pname, GLint* params) {
switch (pname) {
// LOCAL_GL_FRAMEBUFFER_BINDING is equal to
// LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT,
// so we don't need two cases.
case LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT:
if (mScreen) {
*params = mScreen->GetDrawFB();
} else {
raw_fGetIntegerv(pname, params);
}
break;
case LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT:
if (mScreen) {
*params = mScreen->GetReadFB();
} else {
raw_fGetIntegerv(pname, params);
}
break;
case LOCAL_GL_MAX_TEXTURE_SIZE:
MOZ_ASSERT(mMaxTextureSize > 0);
*params = mMaxTextureSize;
@ -2166,7 +2430,17 @@ void GLContext::fGetIntegerv(GLenum pname, GLint* params) const {
void GLContext::fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid* pixels) {
BeforeGLReadCall();
raw_fReadPixels(x, y, width, height, format, type, pixels);
bool didReadPixels = false;
if (mScreen) {
didReadPixels =
mScreen->ReadPixels(x, y, width, height, format, type, pixels);
}
if (!didReadPixels) {
raw_fReadPixels(x, y, width, height, format, type, pixels);
}
AfterGLReadCall();
// Check if GL is giving back 1.0 alpha for
@ -2197,6 +2471,14 @@ void GLContext::fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
}
void GLContext::fDeleteFramebuffers(GLsizei n, const GLuint* names) {
if (mScreen) {
// Notify mScreen which framebuffers we're deleting.
// Otherwise, we will get framebuffer binding mispredictions.
for (int i = 0; i < n; i++) {
mScreen->DeletingFB(names[i]);
}
}
// Avoid crash by flushing before glDeleteFramebuffers. See bug 1194923.
if (mNeedsFlushBeforeDeleteFB) {
fFlush();
@ -2258,24 +2540,97 @@ void GLContext::fTexImage2D(GLenum target, GLint level, GLint internalformat,
type, pixels);
}
UniquePtr<Texture> CreateTexture(GLContext& gl, const gfx::IntSize& size) {
const GLenum target = LOCAL_GL_TEXTURE_2D;
const GLenum format = LOCAL_GL_RGBA;
GLuint GLContext::GetDrawFB() {
if (mScreen) return mScreen->GetDrawFB();
auto tex = MakeUnique<Texture>(gl);
ScopedBindTexture autoTex(&gl, tex->name, target);
GLuint ret = 0;
GetUIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, &ret);
return ret;
}
gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
gl.fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
gl.fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
GLuint GLContext::GetReadFB() {
if (mScreen) return mScreen->GetReadFB();
gl.fTexImage2D(target, 0, format, size.width, size.height, 0, format,
LOCAL_GL_UNSIGNED_BYTE, nullptr);
GLenum bindEnum = IsSupported(GLFeature::split_framebuffer)
? LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
: LOCAL_GL_FRAMEBUFFER_BINDING;
GLuint ret = 0;
GetUIntegerv(bindEnum, &ret);
return ret;
}
GLuint GLContext::GetFB() {
if (mScreen) {
// This has a very important extra assert that checks that we're
// not accidentally ignoring a situation where the draw and read
// FBs differ.
return mScreen->GetFB();
}
GLuint ret = 0;
GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &ret);
return ret;
}
bool GLContext::InitOffscreen(const gfx::IntSize& size,
const SurfaceCaps& caps) {
if (!CreateScreenBuffer(size, caps)) return false;
if (!MakeCurrent()) {
return false;
}
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
fScissor(0, 0, size.width, size.height);
fViewport(0, 0, size.width, size.height);
mCaps = mScreen->mCaps;
MOZ_ASSERT(!mCaps.any);
return true;
}
GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
GLenum aType, const gfx::IntSize& aSize, bool linear) {
GLuint tex = 0;
aGL->fGenTextures(1, &tex);
ScopedBindTexture autoTex(aGL, tex);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
linear ? LOCAL_GL_LINEAR : LOCAL_GL_NEAREST);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
linear ? LOCAL_GL_LINEAR : LOCAL_GL_NEAREST);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, aInternalFormat, aSize.width,
aSize.height, 0, aFormat, aType, nullptr);
return tex;
}
GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats,
const gfx::IntSize& aSize) {
MOZ_ASSERT(aFormats.color_texInternalFormat);
MOZ_ASSERT(aFormats.color_texFormat);
MOZ_ASSERT(aFormats.color_texType);
GLenum internalFormat = aFormats.color_texInternalFormat;
GLenum unpackFormat = aFormats.color_texFormat;
GLenum unpackType = aFormats.color_texType;
if (aGL->IsANGLE()) {
MOZ_ASSERT(internalFormat == LOCAL_GL_RGBA);
MOZ_ASSERT(unpackFormat == LOCAL_GL_RGBA);
MOZ_ASSERT(unpackType == LOCAL_GL_UNSIGNED_BYTE);
internalFormat = LOCAL_GL_BGRA_EXT;
unpackFormat = LOCAL_GL_BGRA_EXT;
}
return CreateTexture(aGL, internalFormat, unpackFormat, unpackType, aSize);
}
uint32_t GetBytesPerTexel(GLenum format, GLenum type) {
// If there is no defined format or type, we're not taking up any memory
if (!format || !type) {
@ -2517,5 +2872,14 @@ void GLContext::OnImplicitMakeCurrentFailure(const char* const funcName) {
<< " mImplicitMakeCurrent.";
}
// -
// These are defined out of line so that we don't need to include
// ISurfaceAllocator.h in SurfaceTypes.h.
SurfaceCaps::SurfaceCaps() = default;
SurfaceCaps::SurfaceCaps(const SurfaceCaps& other) = default;
SurfaceCaps& SurfaceCaps::operator=(const SurfaceCaps& other) = default;
SurfaceCaps::~SurfaceCaps() = default;
} /* namespace gl */
} /* namespace mozilla */

Просмотреть файл

@ -61,7 +61,9 @@ class GLBlitTextureImageHelper;
class GLContext;
class GLLibraryEGL;
class GLReadTexImageHelper;
class GLScreenBuffer;
class SharedSurface;
struct SurfaceCaps;
} // namespace gl
namespace layers {
@ -194,8 +196,6 @@ class GLContext : public GenericAtomicRefCounted,
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(GLContext)
static MOZ_THREAD_LOCAL(uintptr_t) sCurrentContext;
const GLContextDesc mDesc;
bool mImplicitMakeCurrent = false;
bool mUseTLSIsCurrent;
@ -318,6 +318,9 @@ class GLContext : public GenericAtomicRefCounted,
*/
virtual GLuint GetDefaultFramebuffer() { return 0; }
protected:
bool mIsOffscreen;
/**
* mVersion store the OpenGL's version, multiplied by 100. For example, if
* the context is an OpenGL 2.1 context, mVersion value will be 210.
@ -787,6 +790,8 @@ class GLContext : public GenericAtomicRefCounted,
AFTER_GL_CALL;
}
void fBindFramebuffer(GLenum target, GLuint framebuffer);
void fInvalidateFramebuffer(GLenum target, GLsizei numAttachments,
const GLenum* attachments) {
BeforeGLDrawCall();
@ -1172,7 +1177,7 @@ class GLContext : public GenericAtomicRefCounted,
}
private:
void raw_fGetIntegerv(GLenum pname, GLint* params) const {
void raw_fGetIntegerv(GLenum pname, GLint* params) {
BEFORE_GL_CALL;
mSymbols.fGetIntegerv(pname, params);
OnSyncCall();
@ -1180,28 +1185,28 @@ class GLContext : public GenericAtomicRefCounted,
}
public:
void fGetIntegerv(GLenum pname, GLint* params) const;
void fGetIntegerv(GLenum pname, GLint* params);
void GetUIntegerv(GLenum pname, GLuint* params) const {
void GetUIntegerv(GLenum pname, GLuint* params) {
fGetIntegerv(pname, reinterpret_cast<GLint*>(params));
}
template <typename T>
T GetIntAs(GLenum pname) const {
T GetIntAs(GLenum pname) {
static_assert(sizeof(T) == sizeof(GLint), "Invalid T.");
T ret = 0;
fGetIntegerv(pname, (GLint*)&ret);
return ret;
}
void fGetFloatv(GLenum pname, GLfloat* params) const {
void fGetFloatv(GLenum pname, GLfloat* params) {
BEFORE_GL_CALL;
mSymbols.fGetFloatv(pname, params);
OnSyncCall();
AFTER_GL_CALL;
}
void fGetBooleanv(GLenum pname, realGLboolean* params) const {
void fGetBooleanv(GLenum pname, realGLboolean* params) {
BEFORE_GL_CALL;
mSymbols.fGetBooleanv(pname, params);
OnSyncCall();
@ -2005,12 +2010,16 @@ class GLContext : public GenericAtomicRefCounted,
AFTER_GL_CALL;
}
void fBindFramebuffer(GLenum target, GLuint framebuffer) {
private:
friend class SharedSurface;
void raw_fBindFramebuffer(GLenum target, GLuint framebuffer) {
BEFORE_GL_CALL;
mSymbols.fBindFramebuffer(target, framebuffer);
AFTER_GL_CALL;
}
public:
void fBindRenderbuffer(GLenum target, GLuint renderbuffer) {
BEFORE_GL_CALL;
mSymbols.fBindRenderbuffer(target, renderbuffer);
@ -3299,8 +3308,9 @@ class GLContext : public GenericAtomicRefCounted,
// -----------------------------------------------------------------------------
// Constructor
protected:
explicit GLContext(const GLContextDesc&, GLContext* sharedContext = nullptr,
bool canUseTLSIsCurrent = false);
explicit GLContext(CreateContextFlags flags, const SurfaceCaps& caps,
GLContext* sharedContext = nullptr,
bool isOffscreen = false, bool canUseTLSIsCurrent = false);
// -----------------------------------------------------------------------------
// Destructor
@ -3366,6 +3376,28 @@ class GLContext : public GenericAtomicRefCounted,
virtual Maybe<SymbolLoader> GetSymbolLoader() const = 0;
// Before reads from offscreen texture
void GuaranteeResolve();
/*
* Resize the current offscreen buffer. Returns true on success.
* If it returns false, the context should be treated as unusable
* and should be recreated. After the resize, the viewport is not
* changed; glViewport should be called as appropriate.
*
* Only valid if IsOffscreen() returns true.
*/
bool ResizeOffscreen(const gfx::IntSize& size) {
return ResizeScreenBuffer(size);
}
/*
* Return size of this offscreen context.
*
* Only valid if IsOffscreen() returns true.
*/
const gfx::IntSize& OffscreenSize() const;
void BindFB(GLuint fb) {
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
MOZ_GL_ASSERT(this, !fb || fIsFramebuffer(fb));
@ -3379,23 +3411,11 @@ class GLContext : public GenericAtomicRefCounted,
fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb);
}
GLuint GetDrawFB() const {
return GetIntAs<GLuint>(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT);
}
GLuint GetDrawFB();
GLuint GetReadFB() const {
auto bindEnum = LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT;
if (!IsSupported(GLFeature::split_framebuffer)) {
bindEnum = LOCAL_GL_FRAMEBUFFER_BINDING;
}
return GetIntAs<GLuint>(bindEnum);
}
GLuint GetReadFB();
GLuint GetFB() const {
const auto ret = GetDrawFB();
MOZ_ASSERT(ret == GetReadFB());
return ret;
}
GLuint GetFB();
private:
void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype,
@ -3422,6 +3442,9 @@ class GLContext : public GenericAtomicRefCounted,
}
public:
void ForceDirtyScreen();
void CleanDirtyScreen();
virtual GLenum GetPreferredARGB32Format() const { return LOCAL_GL_RGBA; }
virtual GLenum GetPreferredEGLImageTextureTarget() const {
@ -3441,6 +3464,8 @@ class GLContext : public GenericAtomicRefCounted,
const char* extension);
public:
std::map<GLuint, SharedSurface*> mFBOMapping;
enum {
DebugFlagEnabled = 1 << 0,
DebugFlagTrace = 1 << 1,
@ -3482,6 +3507,31 @@ class GLContext : public GenericAtomicRefCounted,
return thisShared == otherShared;
}
bool InitOffscreen(const gfx::IntSize& size, const SurfaceCaps& caps);
protected:
// Note that it does -not- clear the resized buffers.
bool CreateScreenBuffer(const gfx::IntSize& size, const SurfaceCaps& caps) {
if (!IsOffscreenSizeAllowed(size)) return false;
return CreateScreenBufferImpl(size, caps);
}
bool CreateScreenBufferImpl(const gfx::IntSize& size,
const SurfaceCaps& caps);
public:
bool ResizeScreenBuffer(const gfx::IntSize& size);
protected:
SurfaceCaps mCaps;
public:
const SurfaceCaps& Caps() const { return mCaps; }
// Only varies based on bpp16 and alpha.
GLFormats ChooseGLFormats(const SurfaceCaps& caps) const;
bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr);
// Does not check completeness.
@ -3495,10 +3545,14 @@ class GLContext : public GenericAtomicRefCounted,
GLuint* drawFB, GLuint* readFB);
protected:
friend class GLScreenBuffer;
UniquePtr<GLScreenBuffer> mScreen;
SharedSurface* mLockedSurface = nullptr;
public:
void LockSurface(SharedSurface* surf) {
MOZ_ASSERT(!mLockedSurface);
mLockedSurface = surf;
}
@ -3509,7 +3563,9 @@ class GLContext : public GenericAtomicRefCounted,
SharedSurface* GetLockedSurface() const { return mLockedSurface; }
bool IsOffscreen() const { return mDesc.isOffscreen; }
bool IsOffscreen() const { return mIsOffscreen; }
GLScreenBuffer* Screen() const { return mScreen.get(); }
bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
@ -3629,6 +3685,7 @@ class GLContext : public GenericAtomicRefCounted,
void FlushIfHeavyGLCallsSinceLastFlush();
static bool ShouldSpew();
static bool ShouldDumpExts();
bool Readback(SharedSurface* src, gfx::DataSourceSurface* dest);
// --
@ -3693,61 +3750,28 @@ void MarkBitfieldByStrings(const std::vector<nsCString>& strList,
}
}
// -
class Renderbuffer final {
public:
const WeakPtr<GLContext> weakGl;
const GLuint name;
private:
static GLuint Create(GLContext& gl) {
GLuint ret = 0;
gl.fGenRenderbuffers(1, &ret);
return ret;
}
public:
explicit Renderbuffer(GLContext& gl) : weakGl(&gl), name(Create(gl)) {}
~Renderbuffer() {
const RefPtr<GLContext> gl = weakGl.get();
if (!gl->MakeCurrent()) return;
gl->fDeleteRenderbuffers(1, &name);
}
};
// -
class Texture final {
public:
const WeakPtr<GLContext> weakGl;
const GLuint name;
private:
static GLuint Create(GLContext& gl) {
GLuint ret = 0;
gl.fGenTextures(1, &ret);
return ret;
}
public:
explicit Texture(GLContext& gl) : weakGl(&gl), name(Create(gl)) {}
~Texture() {
const RefPtr<GLContext> gl = weakGl.get();
if (!gl->MakeCurrent()) return;
gl->fDeleteTextures(1, &name);
}
};
/**
* Helper function that creates a 2D texture aSize.width x aSize.height with
* storage type specified by aFormats. Returns GL texture object id.
*
* See mozilla::gl::CreateTexture.
*/
UniquePtr<Texture> CreateTexture(GLContext&, const gfx::IntSize& size);
GLuint CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats,
const gfx::IntSize& aSize);
/**
* Helper function that creates a 2D texture aSize.width x aSize.height with
* storage type aInternalFormat. Returns GL texture object id.
*
* Initialize textyre parameters to:
* GL_TEXTURE_MIN_FILTER = GL_LINEAR
* GL_TEXTURE_MAG_FILTER = GL_LINEAR
* GL_TEXTURE_WRAP_S = GL_CLAMP_TO_EDGE
* GL_TEXTURE_WRAP_T = GL_CLAMP_TO_EDGE
*/
GLuint CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
GLenum aType, const gfx::IntSize& aSize,
bool linear = true);
/**
* Helper function that calculates the number of bytes required per

Просмотреть файл

@ -35,7 +35,8 @@ class GLContextCGL : public GLContext {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, override)
GLContextCGL(const GLContextDesc&, NSOpenGLContext* context);
GLContextCGL(CreateContextFlags flags, const SurfaceCaps& caps,
NSOpenGLContext* context, bool isOffscreen);
~GLContextCGL();

Просмотреть файл

@ -22,8 +22,9 @@ class GLContextEAGL : public GLContext {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEAGL, override)
GLContextEAGL(const GLContextDesc&, EAGLContext* context,
GLContext* sharedContext, ContextProfile profile);
GLContextEAGL(CreateContextFlags flags, const SurfaceCaps& caps,
EAGLContext* context, GLContext* sharedContext,
bool isOffscreen, ContextProfile profile);
~GLContextEAGL();

Просмотреть файл

@ -22,13 +22,15 @@ class GLContextEGL : public GLContext {
friend class TextureImageEGL;
static already_AddRefed<GLContextEGL> CreateGLContext(
GLLibraryEGL*, const GLContextDesc&, EGLConfig config, EGLSurface surface,
GLLibraryEGL*, CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, EGLConfig config, EGLSurface surface,
const bool useGles, nsACString* const out_failureId);
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEGL, override)
GLContextEGL(GLLibraryEGL*, const GLContextDesc&, EGLConfig config,
EGLSurface surface, EGLContext context);
GLContextEGL(GLLibraryEGL*, CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, EGLConfig config, EGLSurface surface,
EGLContext context);
~GLContextEGL();
@ -89,10 +91,11 @@ class GLContextEGL : public GLContext {
void Destroy();
static already_AddRefed<GLContextEGL> CreateEGLPBufferOffscreenContext(
const GLContextCreateDesc&, const gfx::IntSize& size,
nsACString* const out_FailureId);
CreateContextFlags flags, const gfx::IntSize& size,
const SurfaceCaps& minCaps, nsACString* const out_FailureId);
static already_AddRefed<GLContextEGL> CreateEGLPBufferOffscreenContextImpl(
const GLContextCreateDesc&, const gfx::IntSize& size, bool aUseGles,
CreateContextFlags flags, const gfx::IntSize& size,
const SurfaceCaps& minCaps, bool aUseGles,
nsACString* const out_FailureId);
#if defined(MOZ_WAYLAND) || defined(MOZ_WIDGET_ANDROID)

Просмотреть файл

@ -20,8 +20,9 @@ class GLContextGLX : public GLContext {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextGLX, override)
static already_AddRefed<GLContextGLX> CreateGLContext(
const GLContextDesc&, Display* display, GLXDrawable drawable,
GLXFBConfig cfg, bool deleteDrawable, gfxXlibSurface* pixmap);
CreateContextFlags flags, const SurfaceCaps& caps, bool isOffscreen,
Display* display, GLXDrawable drawable, GLXFBConfig cfg,
bool deleteDrawable, gfxXlibSurface* pixmap);
static bool FindVisual(Display* display, int screen, bool useWebRender,
bool useAlpha, int* const out_visualId);
@ -65,7 +66,8 @@ class GLContextGLX : public GLContext {
private:
friend class GLContextProviderGLX;
GLContextGLX(const GLContextDesc&, Display* aDisplay, GLXDrawable aDrawable,
GLContextGLX(CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, Display* aDisplay, GLXDrawable aDrawable,
GLXContext aContext, bool aDeleteDrawable, bool aDoubleBuffered,
gfxXlibSurface* aPixmap);

Просмотреть файл

@ -6,8 +6,6 @@
#ifndef GLCONTEXTPROVIDER_H_
#define GLCONTEXTPROVIDER_H_
#include "mozilla/AlreadyAddRefed.h"
#include "GLContextTypes.h"
#include "SurfaceTypes.h"

Просмотреть файл

@ -55,8 +55,9 @@ class CGLLibrary {
CGLLibrary sCGLLibrary;
GLContextCGL::GLContextCGL(const GLContextDesc& desc, NSOpenGLContext* context)
: GLContext(desc), mContext(context) {
GLContextCGL::GLContextCGL(CreateContextFlags flags, const SurfaceCaps& caps,
NSOpenGLContext* context, bool isOffscreen)
: GLContext(flags, caps, nullptr, isOffscreen), mContext(context) {
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback, this);
}
@ -240,10 +241,10 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateForCompositorWidget(
flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
}
nsCString failureUnused;
return CreateHeadless({flags}, &failureUnused);
return CreateHeadless(flags, &failureUnused);
}
static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc) {
static already_AddRefed<GLContextCGL> CreateOffscreenFBOContext(CreateContextFlags flags) {
if (!sCGLLibrary.EnsureInitialized()) {
return nullptr;
}
@ -251,7 +252,6 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
NSOpenGLContext* context = nullptr;
std::vector<NSOpenGLPixelFormatAttribute> attribs;
auto& flags = desc.flags;
if (!StaticPrefs::gl_allow_high_power()) {
flags &= ~CreateContextFlags::HIGH_POWER;
@ -285,17 +285,18 @@ static RefPtr<GLContextCGL> CreateOffscreenFBOContext(GLContextCreateDesc desc)
return nullptr;
}
RefPtr<GLContextCGL> glContext = new GLContextCGL({desc, true}, context);
RefPtr<GLContextCGL> glContext = new GLContextCGL(flags, SurfaceCaps::Any(), context, true);
if (flags & CreateContextFlags::PREFER_MULTITHREADED) {
CGLEnable(glContext->GetCGLContext(), kCGLCEMPEngine);
}
return glContext;
return glContext.forget();
}
already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(const GLContextCreateDesc& desc,
already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(CreateContextFlags flags,
nsACString* const out_failureId) {
auto gl = CreateOffscreenFBOContext(desc);
RefPtr<GLContextCGL> gl;
gl = CreateOffscreenFBOContext(flags);
if (!gl) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_FBO");
return nullptr;
@ -311,9 +312,20 @@ already_AddRefed<GLContext> GLContextProviderCGL::CreateHeadless(const GLContext
}
already_AddRefed<GLContext> GLContextProviderCGL::CreateOffscreen(const IntSize& size,
const GLContextCreateDesc& desc,
const SurfaceCaps& minCaps,
CreateContextFlags flags,
nsACString* const out_failureId) {
return CreateHeadless(desc, out_failureId);
RefPtr<GLContext> gl = CreateHeadless(flags, out_failureId);
if (!gl) {
return nullptr;
}
if (!gl->InitOffscreen(size, minCaps)) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_CGL_INIT");
return nullptr;
}
return gl.forget();
}
static RefPtr<GLContext> gGlobalContext;
@ -325,7 +337,7 @@ GLContext* GLContextProviderCGL::GetGlobalContext() {
MOZ_RELEASE_ASSERT(!gGlobalContext);
nsCString discardFailureId;
RefPtr<GLContext> temp = CreateHeadless({}, &discardFailureId);
RefPtr<GLContext> temp = CreateHeadless(CreateContextFlags::NONE, &discardFailureId);
gGlobalContext = temp;
if (!gGlobalContext) {

Просмотреть файл

@ -21,9 +21,9 @@ namespace gl {
using namespace mozilla::widget;
GLContextEAGL::GLContextEAGL(const GLContextDesc& desc, EAGLContext* context,
GLContext* sharedContext)
: GLContext(desc, sharedContext), mContext(context) {}
GLContextEAGL::GLContextEAGL(CreateContextFlags flags, const SurfaceCaps& caps,
EAGLContext* context, GLContext* sharedContext, bool isOffscreen)
: GLContext(flags, caps, sharedContext, isOffscreen), mContext(context) {}
GLContextEAGL::~GLContextEAGL() {
MakeCurrent();
@ -131,8 +131,8 @@ static GLContextEAGL* GetGlobalContextEAGL() {
return static_cast<GLContextEAGL*>(GLContextProviderEAGL::GetGlobalContext());
}
static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
GLContextEAGL* sharedContext) {
static already_AddRefed<GLContext> CreateEAGLContext(CreateContextFlags flags, bool aOffscreen,
GLContextEAGL* sharedContext) {
EAGLRenderingAPI apis[] = {kEAGLRenderingAPIOpenGLES3, kEAGLRenderingAPIOpenGLES2};
// Try to create a GLES3 context if we can, otherwise fall back to GLES2
@ -154,13 +154,14 @@ static RefPtr<GLContext> CreateEAGLContext(const GLContextDesc& desc,
return nullptr;
}
RefPtr<GLContextEAGL> glContext = new GLContextEAGL(desc, context, sharedContext);
RefPtr<GLContextEAGL> glContext =
new GLContextEAGL(flags, SurfaceCaps::ForRGBA(), context, sharedContext, aOffscreen);
if (!glContext->Init()) {
glContext = nullptr;
return nullptr;
}
return glContext;
return glContext.forget();
}
already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
@ -170,8 +171,8 @@ already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
return nullptr;
}
const GLContextDesc desc = {};
auto glContext = CreateEAGLContext(desc, GetGlobalContextEAGL());
RefPtr<GLContext> glContext =
CreateEAGLContext(CreateContextFlags::NONE, false, GetGlobalContextEAGL());
if (!glContext) {
return nullptr;
}
@ -183,17 +184,20 @@ already_AddRefed<GLContext> GLContextProviderEAGL::CreateForCompositorWidget(
return glContext.forget();
}
already_AddRefed<GLContext> GLContextProviderEAGL::CreateHeadless(
const GLContextCreateDesc& createDesc, nsACString* const out_failureId) {
auto desc = GLContextDesc{createDesc};
desc.isOffcreen = true;
return CreateEAGLContext(desc, GetGlobalContextEAGL()).forget();
already_AddRefed<GLContext> GLContextProviderEAGL::CreateHeadless(CreateContextFlags flags,
nsACString* const out_failureId) {
return CreateEAGLContext(flags, true, GetGlobalContextEAGL());
}
already_AddRefed<GLContext> GLContextProviderEAGL::CreateOffscreen(
const mozilla::gfx::IntSize& size, const GLContextCreateDesc& desc,
const mozilla::gfx::IntSize& size, const SurfaceCaps& caps, CreateContextFlags flags,
nsACString* const out_failureId) {
return CreateHeadless(desc, out_failureId);
RefPtr<GLContext> glContext = CreateHeadless(flags, out_failureId);
if (!glContext->InitOffscreen(size, caps)) {
return nullptr;
}
return glContext.forget();
}
static RefPtr<GLContext> gGlobalContext;

Просмотреть файл

@ -293,9 +293,9 @@ already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
}
const auto desc = GLContextDesc{{flags}, false};
SurfaceCaps caps = SurfaceCaps::Any();
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
egl, desc, config, surface, aUseGles, &discardFailureId);
egl, flags, caps, false, config, surface, aUseGles, &discardFailureId);
if (!gl) {
const auto err = egl->fGetError();
gfxCriticalNote << "Failed to create EGLContext!: " << gfx::hexa(err);
@ -352,10 +352,11 @@ EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget(
}
#endif
GLContextEGL::GLContextEGL(GLLibraryEGL* const egl, const GLContextDesc& desc,
GLContextEGL::GLContextEGL(GLLibraryEGL* const egl, CreateContextFlags flags,
const SurfaceCaps& caps, bool isOffscreen,
EGLConfig config, EGLSurface surface,
EGLContext context)
: GLContext(desc, nullptr, false),
: GLContext(flags, caps, nullptr, isOffscreen, false),
mEgl(egl),
mConfig(config),
mContext(context),
@ -589,10 +590,9 @@ EGLint GLContextEGL::GetBufferAge() const {
#define LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000
already_AddRefed<GLContextEGL> GLContextEGL::CreateGLContext(
GLLibraryEGL* const egl, const GLContextDesc& desc, EGLConfig config,
EGLSurface surface, const bool useGles, nsACString* const out_failureId) {
const auto& flags = desc.flags;
GLLibraryEGL* const egl, CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, EGLConfig config, EGLSurface surface, const bool useGles,
nsACString* const out_failureId) {
std::vector<EGLint> required_attribs;
if (useGles) {
@ -715,7 +715,7 @@ already_AddRefed<GLContextEGL> GLContextEGL::CreateGLContext(
MOZ_ASSERT(context);
RefPtr<GLContextEGL> glContext =
new GLContextEGL(egl, desc, config, surface, context);
new GLContextEGL(egl, flags, caps, isOffscreen, config, surface, context);
if (!glContext->Init()) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_INIT");
return nullptr;
@ -938,9 +938,11 @@ already_AddRefed<GLContext> GLContextProviderEGL::CreateWrappingExisting(
if (!aContext || !aSurface) return nullptr;
const auto& egl = GLLibraryEGL::Get();
SurfaceCaps caps = SurfaceCaps::Any();
EGLConfig config = EGL_NO_CONFIG;
RefPtr<GLContextEGL> gl = new GLContextEGL(
egl, {}, config, (EGLSurface)aSurface, (EGLContext)aContext);
RefPtr<GLContextEGL> gl =
new GLContextEGL(egl, CreateContextFlags::NONE, caps, false, config,
(EGLSurface)aSurface, (EGLContext)aContext);
gl->SetIsDoubleBuffered(true);
gl->mOwnsContext = false;
@ -1011,7 +1013,9 @@ void GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface) {
}
#endif // defined(ANDROID)
static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) {
static void FillOffscreenContextAttribs(bool alpha, bool depth, bool stencil,
bool bpp16, bool es3, bool useGles,
nsTArray<EGLint>* out) {
out->AppendElement(LOCAL_EGL_SURFACE_TYPE);
#if defined(MOZ_WAYLAND)
if (IS_WAYLAND_DISPLAY()) {
@ -1035,22 +1039,38 @@ static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) {
}
out->AppendElement(LOCAL_EGL_RED_SIZE);
out->AppendElement(8);
if (bpp16) {
out->AppendElement(alpha ? 4 : 5);
} else {
out->AppendElement(8);
}
out->AppendElement(LOCAL_EGL_GREEN_SIZE);
out->AppendElement(8);
if (bpp16) {
out->AppendElement(alpha ? 4 : 6);
} else {
out->AppendElement(8);
}
out->AppendElement(LOCAL_EGL_BLUE_SIZE);
out->AppendElement(8);
if (bpp16) {
out->AppendElement(alpha ? 4 : 5);
} else {
out->AppendElement(8);
}
out->AppendElement(LOCAL_EGL_ALPHA_SIZE);
out->AppendElement(8);
if (alpha) {
out->AppendElement(bpp16 ? 4 : 8);
} else {
out->AppendElement(0);
}
out->AppendElement(LOCAL_EGL_DEPTH_SIZE);
out->AppendElement(0);
out->AppendElement(depth ? 16 : 0);
out->AppendElement(LOCAL_EGL_STENCIL_SIZE);
out->AppendElement(0);
out->AppendElement(stencil ? 8 : 0);
// EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
out->AppendElement(LOCAL_EGL_NONE);
@ -1060,8 +1080,6 @@ static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) {
out->AppendElement(0);
}
/*
/// Useful for debugging, but normally unused.
static GLint GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) {
EGLint bits = 0;
egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits);
@ -1069,19 +1087,23 @@ static GLint GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) {
return bits;
}
*/
static EGLConfig ChooseConfig(GLLibraryEGL* const egl,
const GLContextCreateDesc& desc,
const bool useGles) {
static EGLConfig ChooseConfigOffscreen(GLLibraryEGL* egl,
CreateContextFlags flags,
const SurfaceCaps& minCaps,
bool aUseGles,
SurfaceCaps* const out_configCaps) {
nsTArray<EGLint> configAttribList;
FillContextAttribs(bool(desc.flags & CreateContextFlags::PREFER_ES3), useGles,
&configAttribList);
FillOffscreenContextAttribs(minCaps.alpha, minCaps.depth, minCaps.stencil,
minCaps.bpp16,
bool(flags & CreateContextFlags::PREFER_ES3),
aUseGles, &configAttribList);
const EGLint* configAttribs = configAttribList.Elements();
// The sorting dictated by the spec for eglChooseConfig reasonably assures
// that a reasonable 'best' config is on top.
// We're guaranteed to get at least minCaps, and the sorting dictated by the
// spec for eglChooseConfig reasonably assures that a reasonable 'best' config
// is on top.
const EGLint kMaxConfigs = 1;
EGLConfig configs[kMaxConfigs];
EGLint foundConfigs = 0;
@ -1092,22 +1114,34 @@ static EGLConfig ChooseConfig(GLLibraryEGL* const egl,
}
EGLConfig config = configs[0];
*out_configCaps = minCaps; // Pick up any preserve, etc.
out_configCaps->color = true;
out_configCaps->alpha = bool(GetAttrib(egl, config, LOCAL_EGL_ALPHA_SIZE));
out_configCaps->depth = bool(GetAttrib(egl, config, LOCAL_EGL_DEPTH_SIZE));
out_configCaps->stencil =
bool(GetAttrib(egl, config, LOCAL_EGL_STENCIL_SIZE));
out_configCaps->bpp16 = (GetAttrib(egl, config, LOCAL_EGL_RED_SIZE) < 8);
return config;
}
/*static*/
already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLPBufferOffscreenContextImpl(
const GLContextCreateDesc& desc, const mozilla::gfx::IntSize& size,
const bool useGles, nsACString* const out_failureId) {
const bool forceEnableHardware =
bool(desc.flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
CreateContextFlags flags, const mozilla::gfx::IntSize& size,
const SurfaceCaps& minCaps, bool aUseGles,
nsACString* const out_failureId) {
bool forceEnableHardware =
bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
if (!GLLibraryEGL::EnsureInitialized(forceEnableHardware, out_failureId)) {
return nullptr;
}
auto* egl = gl::GLLibraryEGL::Get();
const EGLConfig config = ChooseConfig(egl, desc, useGles);
SurfaceCaps configCaps;
EGLConfig config =
ChooseConfigOffscreen(egl, flags, minCaps, aUseGles, &configCaps);
if (config == EGL_NO_CONFIG) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_NO_CONFIG");
NS_WARNING("Failed to find a compatible config.");
@ -1135,10 +1169,8 @@ GLContextEGL::CreateEGLPBufferOffscreenContextImpl(
return nullptr;
}
auto fullDesc = GLContextDesc{desc};
fullDesc.isOffscreen = true;
RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
egl, fullDesc, config, surface, useGles, out_failureId);
egl, flags, configCaps, true, config, surface, aUseGles, out_failureId);
if (!gl) {
NS_WARNING("Failed to create GLContext from PBuffer");
egl->fDestroySurface(egl->Display(), surface);
@ -1152,33 +1184,34 @@ GLContextEGL::CreateEGLPBufferOffscreenContextImpl(
}
already_AddRefed<GLContextEGL> GLContextEGL::CreateEGLPBufferOffscreenContext(
const GLContextCreateDesc& desc, const mozilla::gfx::IntSize& size,
nsACString* const out_failureId) {
CreateContextFlags flags, const mozilla::gfx::IntSize& size,
const SurfaceCaps& minCaps, nsACString* const out_failureId) {
RefPtr<GLContextEGL> gl = CreateEGLPBufferOffscreenContextImpl(
desc, size, /* useGles */ false, out_failureId);
flags, size, minCaps, /* aUseGles */ false, out_failureId);
if (!gl) {
gl = CreateEGLPBufferOffscreenContextImpl(desc, size, /* useGles */ true,
out_failureId);
gl = CreateEGLPBufferOffscreenContextImpl(
flags, size, minCaps, /* aUseGles */ true, out_failureId);
}
return gl.forget();
}
/*static*/
already_AddRefed<GLContext> GLContextProviderEGL::CreateHeadless(
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
CreateContextFlags flags, nsACString* const out_failureId) {
mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
return GLContextEGL::CreateEGLPBufferOffscreenContext(desc, dummySize,
out_failureId);
SurfaceCaps dummyCaps = SurfaceCaps::Any();
return GLContextEGL::CreateEGLPBufferOffscreenContext(
flags, dummySize, dummyCaps, out_failureId);
}
// Under EGL, on Android, pbuffers are supported fine, though
// often without the ability to texture from them directly.
/*static*/
already_AddRefed<GLContext> GLContextProviderEGL::CreateOffscreen(
const mozilla::gfx::IntSize& size, const GLContextCreateDesc& desc,
nsACString* const out_failureId) {
const mozilla::gfx::IntSize& size, const SurfaceCaps& minCaps,
CreateContextFlags flags, nsACString* const out_failureId) {
bool forceEnableHardware =
bool(desc.flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
if (!GLLibraryEGL::EnsureInitialized(
forceEnableHardware, out_failureId)) { // Needed for IsANGLE().
return nullptr;
@ -1192,17 +1225,37 @@ already_AddRefed<GLContext> GLContextProviderEGL::CreateOffscreen(
}
#if defined(MOZ_WIDGET_ANDROID)
// Using a headless context loses the depth and/or stencil
// Using a headless context loses the SurfaceCaps
// which can cause a loss of depth and/or stencil
canOffscreenUseHeadless = false;
#endif // defined(MOZ_WIDGET_ANDROID)
RefPtr<GLContext> gl;
SurfaceCaps minOffscreenCaps = minCaps;
if (canOffscreenUseHeadless) {
gl = CreateHeadless(desc, out_failureId);
gl = CreateHeadless(flags, out_failureId);
if (!gl) {
return nullptr;
}
} else {
gl = GLContextEGL::CreateEGLPBufferOffscreenContext(desc, size,
out_failureId);
gl = GLContextEGL::CreateEGLPBufferOffscreenContext(
flags, size, minOffscreenCaps, out_failureId);
if (!gl) return nullptr;
// Pull the actual resulting caps to ensure that our offscreen matches our
// backbuffer.
minOffscreenCaps.alpha = gl->Caps().alpha;
minOffscreenCaps.depth = gl->Caps().depth;
minOffscreenCaps.stencil = gl->Caps().stencil;
}
// Init the offscreen with the updated offscreen caps.
if (!gl->InitOffscreen(size, minOffscreenCaps)) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_OFFSCREEN");
return nullptr;
}
return gl.forget();
}

Просмотреть файл

@ -461,8 +461,9 @@ void GLXLibrary::AfterGLXCall() const {
}
already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext(
const GLContextDesc& desc, Display* display, GLXDrawable drawable,
GLXFBConfig cfg, bool deleteDrawable, gfxXlibSurface* pixmap) {
CreateContextFlags flags, const SurfaceCaps& caps, bool isOffscreen,
Display* display, GLXDrawable drawable, GLXFBConfig cfg,
bool deleteDrawable, gfxXlibSurface* pixmap) {
GLXLibrary& glx = sGLXLibrary;
int db = 0;
@ -502,7 +503,7 @@ already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext(
attrib_list.AppendElements(memory_purge_attribs,
MOZ_ARRAY_LENGTH(memory_purge_attribs));
}
if (!(desc.flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
if (!(flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
int core_attribs[] = {
LOCAL_GLX_CONTEXT_MAJOR_VERSION_ARB,
3,
@ -524,8 +525,8 @@ already_AddRefed<GLContextGLX> GLContextGLX::CreateGLContext(
}
if (context) {
glContext = new GLContextGLX(desc, display, drawable, context,
deleteDrawable, db, pixmap);
glContext = new GLContextGLX(flags, caps, isOffscreen, display, drawable,
context, deleteDrawable, db, pixmap);
if (!glContext->Init()) error = true;
} else {
error = true;
@ -647,11 +648,12 @@ bool GLContextGLX::RestoreDrawable() {
return mGLX->fMakeCurrent(mDisplay, mDrawable, mContext);
}
GLContextGLX::GLContextGLX(const GLContextDesc& desc, Display* aDisplay,
GLContextGLX::GLContextGLX(CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, Display* aDisplay,
GLXDrawable aDrawable, GLXContext aContext,
bool aDeleteDrawable, bool aDoubleBuffered,
gfxXlibSurface* aPixmap)
: GLContext(desc, nullptr),
: GLContext(flags, caps, nullptr, isOffscreen),
mContext(aContext),
mDisplay(aDisplay),
mDrawable(aDrawable),
@ -684,8 +686,10 @@ already_AddRefed<GLContext> GLContextProviderGLX::CreateWrappingExisting(
}
if (aContext && aSurface) {
SurfaceCaps caps = SurfaceCaps::Any();
RefPtr<GLContextGLX> glContext =
new GLContextGLX({},
new GLContextGLX(CreateContextFlags::NONE, caps,
false, // Offscreen
(Display*)DefaultXDisplay(), // Display
(GLXDrawable)aSurface, (GLXContext)aContext,
false, // aDeleteDrawable,
@ -733,8 +737,9 @@ already_AddRefed<GLContext> CreateForWidget(Display* aXDisplay, Window aXWindow,
} else {
flags = CreateContextFlags::REQUIRE_COMPAT_PROFILE;
}
return GLContextGLX::CreateGLContext({{flags}, false}, aXDisplay, aXWindow,
config, false, nullptr);
return GLContextGLX::CreateGLContext(flags, SurfaceCaps::Any(), false,
aXDisplay, aXWindow, config, false,
nullptr);
}
already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget(
@ -752,6 +757,7 @@ already_AddRefed<GLContext> GLContextProviderGLX::CreateForCompositorWidget(
}
static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen,
const SurfaceCaps& minCaps,
ScopedXFree<GLXFBConfig>* const out_scopedConfigArr,
GLXFBConfig* const out_config, int* const out_visid) {
ScopedXFree<GLXFBConfig>& scopedConfigArr = *out_scopedConfigArr;
@ -767,11 +773,11 @@ static bool ChooseConfig(GLXLibrary* glx, Display* display, int screen,
LOCAL_GLX_BLUE_SIZE,
8,
LOCAL_GLX_ALPHA_SIZE,
8,
minCaps.alpha ? 8 : 0,
LOCAL_GLX_DEPTH_SIZE,
0,
minCaps.depth ? 16 : 0,
LOCAL_GLX_STENCIL_SIZE,
0,
minCaps.stencil ? 8 : 0,
0};
int numConfigs = 0;
@ -961,7 +967,7 @@ bool GLContextGLX::FindFBConfigForWindow(
}
static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(
const GLContextCreateDesc& desc, const IntSize& size,
CreateContextFlags flags, const IntSize& size, const SurfaceCaps& minCaps,
nsACString* const out_failureId) {
GLXLibrary* glx = &sGLXLibrary;
if (!glx->EnsureInitialized()) return nullptr;
@ -972,7 +978,8 @@ static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(
ScopedXFree<GLXFBConfig> scopedConfigArr;
GLXFBConfig config;
int visid;
if (!ChooseConfig(glx, display, screen, &scopedConfigArr, &config, &visid)) {
if (!ChooseConfig(glx, display, screen, minCaps, &scopedConfigArr, &config,
&visid)) {
NS_WARNING("Failed to find a compatible config.");
return nullptr;
}
@ -1004,24 +1011,33 @@ static already_AddRefed<GLContextGLX> CreateOffscreenPixmapContext(
bool serverError = xErrorHandler.SyncAndGetError(display);
if (error || serverError) return nullptr;
auto fullDesc = GLContextDesc{desc};
fullDesc.isOffscreen = true;
return GLContextGLX::CreateGLContext(fullDesc, display, pixmap, config, true,
surface);
return GLContextGLX::CreateGLContext(flags, minCaps, true, display, pixmap,
config, true, surface);
}
/*static*/
already_AddRefed<GLContext> GLContextProviderGLX::CreateHeadless(
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
CreateContextFlags flags, nsACString* const out_failureId) {
IntSize dummySize = IntSize(16, 16);
return CreateOffscreenPixmapContext(desc, dummySize, out_failureId);
SurfaceCaps dummyCaps = SurfaceCaps::Any();
return CreateOffscreenPixmapContext(flags, dummySize, dummyCaps,
out_failureId);
}
/*static*/
already_AddRefed<GLContext> GLContextProviderGLX::CreateOffscreen(
const IntSize& size, const GLContextCreateDesc& desc,
const IntSize& size, const SurfaceCaps& minCaps, CreateContextFlags flags,
nsACString* const out_failureId) {
return CreateOffscreenPixmapContext(desc, size, out_failureId);
RefPtr<GLContext> gl;
gl = CreateOffscreenPixmapContext(flags, size, minCaps, out_failureId);
if (!gl) return nullptr;
if (!gl->InitOffscreen(size, minCaps)) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_GLX_INIT");
return nullptr;
}
return gl.forget();
}
/*static*/

Просмотреть файл

@ -66,12 +66,12 @@ class GL_CONTEXT_PROVIDER_NAME {
* @return Context to use for offscreen rendering
*/
static already_AddRefed<GLContext> CreateOffscreen(
const mozilla::gfx::IntSize& size, const GLContextCreateDesc&,
nsACString* const out_failureId);
const mozilla::gfx::IntSize& size, const SurfaceCaps& minCaps,
CreateContextFlags flags, nsACString* const out_failureId);
// Just create a context. We'll add offscreen stuff ourselves.
static already_AddRefed<GLContext> CreateHeadless(
const GLContextCreateDesc&, nsACString* const out_failureId);
CreateContextFlags flags, nsACString* const out_failureId);
/**
* Create wrapping Gecko GLContext for external gl context.

Просмотреть файл

@ -22,14 +22,14 @@ already_AddRefed<GLContext> GLContextProviderNull::CreateWrappingExisting(
}
already_AddRefed<GLContext> GLContextProviderNull::CreateOffscreen(
const gfx::IntSize&, const GLContextCreateDesc&,
const gfx::IntSize&, const SurfaceCaps&, CreateContextFlags,
nsACString* const out_failureId) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_NULL");
return nullptr;
}
already_AddRefed<GLContext> GLContextProviderNull::CreateHeadless(
const GLContextCreateDesc&, nsACString* const out_failureId) {
CreateContextFlags, nsACString* const out_failureId) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_NULL");
return nullptr;
}

Просмотреть файл

@ -265,18 +265,20 @@ void WGLLibrary::Reset() {
}
}
GLContextWGL::GLContextWGL(const GLContextDesc& desc, HDC aDC, HGLRC aContext,
GLContextWGL::GLContextWGL(CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, HDC aDC, HGLRC aContext,
HWND aWindow)
: GLContext(desc, nullptr, false),
: GLContext(flags, caps, nullptr, isOffscreen),
mDC(aDC),
mContext(aContext),
mWnd(aWindow),
mPBuffer(nullptr),
mPixelFormat(0) {}
GLContextWGL::GLContextWGL(const GLContextDesc& desc, HANDLE aPbuffer, HDC aDC,
GLContextWGL::GLContextWGL(CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, HANDLE aPbuffer, HDC aDC,
HGLRC aContext, int aPixelFormat)
: GLContext(desc, nullptr, false),
: GLContext(flags, caps, nullptr, isOffscreen),
mDC(aDC),
mContext(aContext),
mWnd(nullptr),
@ -439,7 +441,9 @@ static RefPtr<GLContext> CreateForWidget(const HWND window,
const auto context = sWGLLib.CreateContextWithFallback(dc, false);
if (!context) return nullptr;
const RefPtr<GLContextWGL> gl = new GLContextWGL({}, dc, context);
SurfaceCaps caps = SurfaceCaps::ForRGBA();
const RefPtr<GLContextWGL> gl = new GLContextWGL(
CreateContextFlags::NONE, SurfaceCaps::ForRGBA(), false, dc, context);
cleanupDc.release();
gl->mIsDoubleBuffered = true;
if (!gl->Init()) return nullptr;
@ -461,7 +465,7 @@ already_AddRefed<GLContext> GLContextProviderWGL::CreateForCompositorWidget(
/*static*/
already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless(
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
const CreateContextFlags flags, nsACString* const out_failureId) {
auto& wgl = sWGLLib;
if (!wgl.EnsureInitialized()) return nullptr;
@ -505,9 +509,10 @@ already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless(
const auto context = wgl.CreateContextWithFallback(dc, true);
if (!context) return nullptr;
const auto fullDesc = GLContextDesc{desc, true};
const bool isOffscreen = true;
const RefPtr<GLContextWGL> gl =
new GLContextWGL(fullDesc, pbuffer, dc, context, chosenFormat);
new GLContextWGL(flags, SurfaceCaps::Any(), isOffscreen, pbuffer, dc,
context, chosenFormat);
cleanupPbuffer.release();
cleanupDc.release();
if (!gl->Init()) return nullptr;
@ -517,10 +522,16 @@ already_AddRefed<GLContext> GLContextProviderWGL::CreateHeadless(
/*static*/
already_AddRefed<GLContext> GLContextProviderWGL::CreateOffscreen(
const IntSize& size, const GLContextCreateDesc& desc,
const IntSize& size, const SurfaceCaps& minCaps, CreateContextFlags flags,
nsACString* const out_failureId) {
*out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WGL_INIT");
return CreateHeadless(desc, out_failureId);
RefPtr<GLContext> gl = CreateHeadless(flags, out_failureId);
if (!gl) return nullptr;
if (!gl->InitOffscreen(size, minCaps)) return nullptr;
return gl.forget();
}
/*static*/

Просмотреть файл

@ -41,22 +41,24 @@ already_AddRefed<GLContext> GLContextProviderWayland::CreateForCompositorWidget(
/*static*/
already_AddRefed<GLContext> GLContextProviderWayland::CreateHeadless(
const GLContextCreateDesc& desc, nsACString* const out_failureId) {
CreateContextFlags flags, nsACString* const out_failureId) {
if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
return sGLContextProviderGLX.CreateHeadless(desc, out_failureId);
return sGLContextProviderGLX.CreateHeadless(flags, out_failureId);
} else {
return sGLContextProviderEGL.CreateHeadless(desc, out_failureId);
return sGLContextProviderEGL.CreateHeadless(flags, out_failureId);
}
}
/*static*/
already_AddRefed<GLContext> GLContextProviderWayland::CreateOffscreen(
const IntSize& size, const GLContextCreateDesc& desc,
const IntSize& size, const SurfaceCaps& minCaps, CreateContextFlags flags,
nsACString* const out_failureId) {
if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
return sGLContextProviderGLX.CreateOffscreen(size, desc, out_failureId);
return sGLContextProviderGLX.CreateOffscreen(size, minCaps, flags,
out_failureId);
} else {
return sGLContextProviderEGL.CreateOffscreen(size, desc, out_failureId);
return sGLContextProviderEGL.CreateOffscreen(size, minCaps, flags,
out_failureId);
}
}

Просмотреть файл

@ -18,6 +18,17 @@ enum class GLContextType { Unknown, WGL, CGL, GLX, EGL, EAGL };
enum class OriginPos : uint8_t { TopLeft, BottomLeft };
struct GLFormats {
GLenum color_texInternalFormat = 0;
GLenum color_texFormat = 0;
GLenum color_texType = 0;
GLenum color_rbFormat = 0;
GLenum depthStencil = 0;
GLenum depth = 0;
GLenum stencil = 0;
};
enum class CreateContextFlags : uint16_t {
NONE = 0,
REQUIRE_COMPAT_PROFILE = 1 << 0,
@ -37,14 +48,6 @@ enum class CreateContextFlags : uint16_t {
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)
struct GLContextCreateDesc {
CreateContextFlags flags = CreateContextFlags::NONE;
};
struct GLContextDesc final : public GLContextCreateDesc {
bool isOffscreen = false;
};
} /* namespace gl */
} /* namespace mozilla */

Просмотреть файл

@ -17,11 +17,13 @@ class GLContextWGL final : public GLContext {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextWGL, override)
// From Window: (possibly for offscreen!)
GLContextWGL(const GLContextDesc&, HDC aDC, HGLRC aContext,
GLContextWGL(CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, HDC aDC, HGLRC aContext,
HWND aWindow = nullptr);
// From PBuffer
GLContextWGL(const GLContextDesc&, HANDLE aPbuffer, HDC aDC, HGLRC aContext,
GLContextWGL(CreateContextFlags flags, const SurfaceCaps& caps,
bool isOffscreen, HANDLE aPbuffer, HDC aDC, HGLRC aContext,
int aPixelFormat);
~GLContextWGL();

Просмотреть файл

@ -333,7 +333,8 @@ bool GLLibraryEGL::ReadbackEGLImage(EGLImage image,
StaticMutexAutoUnlock lock(sMutex);
if (!mReadbackGL) {
nsCString discardFailureId;
mReadbackGL = gl::GLContextProvider::CreateHeadless({}, &discardFailureId);
mReadbackGL = gl::GLContextProvider::CreateHeadless(
gl::CreateContextFlags::NONE, &discardFailureId);
}
ScopedTexture destTex(mReadbackGL);

Просмотреть файл

@ -385,21 +385,21 @@ class GLLibraryEGL final {
return mIsWARP;
}
bool HasKHRImageBase() const {
bool HasKHRImageBase() {
return IsExtensionSupported(KHR_image) ||
IsExtensionSupported(KHR_image_base);
}
bool HasKHRImagePixmap() const {
bool HasKHRImagePixmap() {
return IsExtensionSupported(KHR_image) ||
IsExtensionSupported(KHR_image_pixmap);
}
bool HasKHRImageTexture2D() const {
bool HasKHRImageTexture2D() {
return IsExtensionSupported(KHR_gl_texture_2D_image);
}
bool HasANGLESurfaceD3DTexture2DShareHandle() const {
bool HasANGLESurfaceD3DTexture2DShareHandle() {
return IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle);
}

Просмотреть файл

@ -424,6 +424,7 @@ already_AddRefed<DataSourceSurface> ReadBackSurface(GLContext* gl,
bool aYInvert,
SurfaceFormat aFormat) {
gl->MakeCurrent();
gl->GuaranteeResolve();
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);

Просмотреть файл

@ -5,82 +5,607 @@
#include "GLScreenBuffer.h"
#include <cstring>
#include "CompositorTypes.h"
#include "mozilla/StaticPrefs_webgl.h"
#include "GLContext.h"
#include "GLBlitHelper.h"
#include "GLReadTexImageHelper.h"
#include "SharedSurfaceEGL.h"
#include "SharedSurfaceGL.h"
#include "ScopedGLHelpers.h"
#include "gfx2DGlue.h"
#include "MozFramebuffer.h"
#include "SharedSurface.h"
#include "../layers/ipc/ShadowLayers.h"
#include "mozilla/layers/TextureForwarder.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#ifdef XP_WIN
# include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
# include "SharedSurfaceD3D11Interop.h" // for SurfaceFactory_D3D11Interop
# include "mozilla/gfx/DeviceManagerDx.h"
#endif
#ifdef XP_MACOSX
# include "SharedSurfaceIO.h"
#endif
#ifdef MOZ_X11
# include "GLXLibrary.h"
# include "SharedSurfaceGLX.h"
#endif
#ifdef MOZ_WAYLAND
# include "gfxPlatformGtk.h"
# include "SharedSurfaceDMABUF.h"
#endif
namespace mozilla::gl {
// -
// SwapChainPresenter
UniquePtr<GLScreenBuffer> GLScreenBuffer::Create(GLContext* gl,
const gfx::IntSize& size,
const SurfaceCaps& caps) {
UniquePtr<GLScreenBuffer> ret;
UniquePtr<SwapChainPresenter> SwapChain::Acquire(const gfx::IntSize& size) {
MOZ_ASSERT(mFactory);
auto back = mFactory->CreateShared(size);
if (!back) return nullptr;
layers::TextureFlags flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
if (!caps.premultAlpha) {
flags |= layers::TextureFlags::NON_PREMULTIPLIED;
}
auto ret = MakeUnique<SwapChainPresenter>(*this);
ret->SwapBackBuffer(std::move(back));
UniquePtr<SurfaceFactory> factory =
MakeUnique<SurfaceFactory_Basic>(gl, caps, flags);
ret.reset(new GLScreenBuffer(gl, caps, std::move(factory)));
return ret;
}
// -
SwapChainPresenter::SwapChainPresenter(SwapChain& swapChain)
: mSwapChain(&swapChain) {
MOZ_RELEASE_ASSERT(mSwapChain->mPresenter == nullptr);
mSwapChain->mPresenter = this;
/* static */
UniquePtr<SurfaceFactory> GLScreenBuffer::CreateFactory(
GLContext* gl, const SurfaceCaps& caps,
layers::KnowsCompositor* compositorConnection,
const layers::TextureFlags& flags) {
const auto& ipcChannel = compositorConnection->GetTextureForwarder();
const auto& backend = compositorConnection->GetCompositorBackendType();
bool useANGLE = compositorConnection->GetCompositorUseANGLE();
return CreateFactory(gl, caps, ipcChannel, backend, useANGLE, flags);
}
SwapChainPresenter::~SwapChainPresenter() {
if (!mSwapChain) return;
MOZ_RELEASE_ASSERT(mSwapChain->mPresenter == this);
mSwapChain->mPresenter = nullptr;
/* static */
UniquePtr<SurfaceFactory> GLScreenBuffer::CreateFactory(
GLContext* gl, const SurfaceCaps& caps,
layers::LayersIPCChannel* ipcChannel, layers::LayersBackend backend,
bool useANGLE, const layers::TextureFlags& flags) {
const bool useGl =
!StaticPrefs::webgl_force_layers_readback() &&
(backend == layers::LayersBackend::LAYERS_OPENGL ||
(backend == layers::LayersBackend::LAYERS_WR && !useANGLE));
const bool useD3D =
!StaticPrefs::webgl_force_layers_readback() &&
(backend == layers::LayersBackend::LAYERS_D3D11 ||
(backend == layers::LayersBackend::LAYERS_WR && useANGLE));
auto newFront = SwapBackBuffer(nullptr);
if (newFront) {
mSwapChain->mFrontBuffer = std::move(newFront);
UniquePtr<SurfaceFactory> factory = nullptr;
if (useGl) {
#if defined(XP_MACOSX)
factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
#elif defined(MOZ_WAYLAND)
if (gl->GetContextType() == GLContextType::EGL) {
if (gfxPlatformGtk::GetPlatform()->UseWaylandDMABufWebGL()) {
factory =
MakeUnique<SurfaceFactory_DMABUF>(gl, caps, ipcChannel, flags);
}
}
#elif defined(MOZ_X11)
if (sGLXLibrary.UseTextureFromPixmap())
factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
#elif defined(MOZ_WIDGET_UIKIT)
factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, ipcChannel,
mFlags);
#elif defined(MOZ_WIDGET_ANDROID)
if (XRE_IsParentProcess() && !StaticPrefs::webgl_enable_surface_texture()) {
factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
} else {
factory =
SurfaceFactory_SurfaceTexture::Create(gl, caps, ipcChannel, flags);
}
#else
if (gl->GetContextType() == GLContextType::EGL) {
if (XRE_IsParentProcess()) {
factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
}
}
#endif
} else if (useD3D) {
#ifdef XP_WIN
// Ensure devices initialization. SharedSurfaceANGLE and
// SharedSurfaceD3D11Interop use them. The devices are lazily initialized
// with WebRender to reduce memory usage.
if (XRE_IsContentProcess()) {
gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
}
// Enable surface sharing only if ANGLE and compositing devices
// are both WARP or both not WARP
gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
MOZ_ASSERT(dm);
if (gl->IsANGLE() && (gl->IsWARP() == dm->IsWARP()) &&
dm->TextureSharingWorks()) {
factory =
SurfaceFactory_ANGLEShareHandle::Create(gl, caps, ipcChannel, flags);
}
if (!factory && StaticPrefs::webgl_dxgl_enabled()) {
factory =
SurfaceFactory_D3D11Interop::Create(gl, caps, ipcChannel, flags);
}
#endif
}
#ifdef MOZ_X11
if (!factory && sGLXLibrary.UseTextureFromPixmap()) {
factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
}
#endif
return factory;
}
GLScreenBuffer::GLScreenBuffer(GLContext* gl, const SurfaceCaps& caps,
UniquePtr<SurfaceFactory> factory)
: mGL(gl),
mCaps(caps),
mFactory(std::move(factory)),
mUserDrawFB(0),
mUserReadFB(0),
mInternalDrawFB(0),
mInternalReadFB(0)
#ifdef DEBUG
,
mInInternalMode_DrawFB(true),
mInInternalMode_ReadFB(true)
#endif
{
}
GLScreenBuffer::~GLScreenBuffer() {
mFactory = nullptr;
mRead = nullptr;
if (!mBack) return;
// Detach mBack cleanly.
mBack->Surf()->ProducerRelease();
}
void GLScreenBuffer::BindFB(GLuint fb) {
GLuint drawFB = DrawFB();
GLuint readFB = ReadFB();
mUserDrawFB = fb;
mUserReadFB = fb;
mInternalDrawFB = (fb == 0) ? drawFB : fb;
mInternalReadFB = (fb == 0) ? readFB : fb;
if (mInternalDrawFB == mInternalReadFB) {
mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
} else {
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
}
#ifdef DEBUG
mInInternalMode_DrawFB = false;
mInInternalMode_ReadFB = false;
#endif
}
void GLScreenBuffer::BindDrawFB(GLuint fb) {
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
GLuint drawFB = DrawFB();
mUserDrawFB = fb;
mInternalDrawFB = (fb == 0) ? drawFB : fb;
mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
#ifdef DEBUG
mInInternalMode_DrawFB = false;
#endif
}
void GLScreenBuffer::BindReadFB(GLuint fb) {
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
GLuint readFB = ReadFB();
mUserReadFB = fb;
mInternalReadFB = (fb == 0) ? readFB : fb;
mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
#ifdef DEBUG
mInInternalMode_ReadFB = false;
#endif
}
void GLScreenBuffer::BindReadFB_Internal(GLuint fb) {
MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
mInternalReadFB = mUserReadFB = fb;
mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
#ifdef DEBUG
mInInternalMode_ReadFB = true;
#endif
}
GLuint GLScreenBuffer::GetDrawFB() const {
#ifdef DEBUG
MOZ_ASSERT(!mInInternalMode_DrawFB);
// Don't need a branch here, because:
// LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING ==
// 0x8CA6 We use raw_ here because this is debug code and we need to see what
// the driver thinks.
GLuint actual = 0;
mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
GLuint predicted = mInternalDrawFB;
if (predicted != actual && !mGL->CheckContextLost()) {
printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n",
predicted, actual);
MOZ_ASSERT(false, "Draw FB binding misprediction!");
}
#endif
return mUserDrawFB;
}
GLuint GLScreenBuffer::GetReadFB() const {
#ifdef DEBUG
MOZ_ASSERT(!mInInternalMode_ReadFB);
// We use raw_ here because this is debug code and we need to see what
// the driver thinks.
GLuint actual = 0;
if (mGL->IsSupported(GLFeature::split_framebuffer))
mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT,
(GLint*)&actual);
else
mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
GLuint predicted = mInternalReadFB;
if (predicted != actual && !mGL->CheckContextLost()) {
printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
predicted, actual);
MOZ_ASSERT(false, "Read FB binding misprediction!");
}
#endif
return mUserReadFB;
}
GLuint GLScreenBuffer::GetFB() const {
MOZ_ASSERT(GetDrawFB() == GetReadFB());
return GetDrawFB();
}
void GLScreenBuffer::DeletingFB(GLuint fb) {
if (fb == mInternalDrawFB) {
mInternalDrawFB = 0;
mUserDrawFB = 0;
}
if (fb == mInternalReadFB) {
mInternalReadFB = 0;
mUserReadFB = 0;
}
}
UniquePtr<SharedSurface> SwapChainPresenter::SwapBackBuffer(
UniquePtr<SharedSurface> back) {
if (mBackBuffer) {
mBackBuffer->UnlockProd();
mBackBuffer->ProducerRelease();
mBackBuffer->Commit();
bool GLScreenBuffer::CopyTexImage2D(GLenum target, GLint level,
GLenum internalformat, GLint x, GLint y,
GLsizei width, GLsizei height,
GLint border) {
SharedSurface* surf;
if (GetReadFB() == 0) {
surf = SharedSurf();
} else {
surf = mGL->mFBOMapping[GetReadFB()];
}
auto old = std::move(mBackBuffer);
mBackBuffer = std::move(back);
if (mBackBuffer) {
mBackBuffer->WaitForBufferOwnership();
mBackBuffer->ProducerAcquire();
mBackBuffer->LockProd();
if (surf) {
return surf->CopyTexImage2D(target, level, internalformat, x, y, width,
height, border);
}
return old;
return false;
}
GLuint SwapChainPresenter::Fb() const {
if (!mBackBuffer) return 0;
const auto& fb = mBackBuffer->mFb;
if (!fb) return 0;
return fb->mFB;
bool GLScreenBuffer::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid* pixels) {
// If the currently bound framebuffer is backed by a SharedSurface
// then it might want to override how we read pixel data from it.
// This is normally only the default framebuffer, but we can also
// have SharedSurfaces bound to other framebuffers when doing
// readback for BasicLayers.
SharedSurface* surf;
if (GetReadFB() == 0) {
surf = SharedSurf();
} else {
surf = mGL->mFBOMapping[GetReadFB()];
}
if (surf) {
return surf->ReadPixels(x, y, width, height, format, type, pixels);
}
return false;
}
// -
// SwapChain
void GLScreenBuffer::Morph(UniquePtr<SurfaceFactory> newFactory) {
MOZ_RELEASE_ASSERT(newFactory, "newFactory must not be null");
mFactory = std::move(newFactory);
}
SwapChain::SwapChain() = default;
bool GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size) {
ScopedBindFramebuffer autoFB(mGL);
SwapChain::~SwapChain() {
if (mPresenter) {
// Out of order destruction, but ok.
(void)mPresenter->SwapBackBuffer(nullptr);
mPresenter->mSwapChain = nullptr;
mPresenter = nullptr;
const bool readNeedsUnlock = (mRead && SharedSurf());
if (readNeedsUnlock) {
SharedSurf()->UnlockProd();
}
surf->LockProd();
if (mRead && surf->mAttachType == SharedSurf()->mAttachType &&
size == Size()) {
// Same size, same type, ready for reuse!
mRead->Attach(surf);
} else {
UniquePtr<ReadBuffer> read = CreateRead(surf);
if (!read) {
surf->UnlockProd();
if (readNeedsUnlock) {
SharedSurf()->LockProd();
}
return false;
}
mRead = std::move(read);
}
// Check that we're all set up.
MOZ_ASSERT(SharedSurf() == surf);
return true;
}
bool GLScreenBuffer::Swap(const gfx::IntSize& size) {
RefPtr<layers::SharedSurfaceTextureClient> newBack =
mFactory->NewTexClient(size);
if (!newBack) return false;
// In the case of DXGL interop, the new surface needs to be acquired before
// it is attached so that the interop surface is locked, which populates
// the GL renderbuffer. This results in the renderbuffer being ready and
// attachment to framebuffer succeeds in Attach() call.
newBack->Surf()->ProducerAcquire();
if (!Attach(newBack->Surf(), size)) {
newBack->Surf()->ProducerRelease();
return false;
}
// Attach was successful.
mFront = mBack;
mBack = newBack;
if (mCaps.preserve && mFront && mBack) {
auto src = mFront->Surf();
auto dest = mBack->Surf();
// uint32_t srcPixel = ReadPixel(src);
// uint32_t destPixel = ReadPixel(dest);
// printf_stderr("Before: src: 0x%08x, dest: 0x%08x\n", srcPixel,
// destPixel);
#ifdef DEBUG
GLContext::LocalErrorScope errorScope(*mGL);
#endif
if (!SharedSurface::ProdCopy(src, dest, mFactory.get())) {
newBack->Surf()->ProducerRelease();
return false;
}
#ifdef DEBUG
MOZ_ASSERT(!errorScope.GetError());
#endif
// srcPixel = ReadPixel(src);
// destPixel = ReadPixel(dest);
// printf_stderr("After: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel);
}
// XXX: We would prefer to fence earlier on platforms that don't need
// the full ProducerAcquire/ProducerRelease semantics, so that the fence
// doesn't include the copy operation. Unfortunately, the current API
// doesn't expose a good way to do that.
if (mFront) {
mFront->Surf()->ProducerRelease();
}
return true;
}
bool GLScreenBuffer::Resize(const gfx::IntSize& size) {
RefPtr<layers::SharedSurfaceTextureClient> newBack =
mFactory->NewTexClient(size);
if (!newBack) return false;
if (!Attach(newBack->Surf(), size)) return false;
if (mBack) mBack->Surf()->ProducerRelease();
mBack = newBack;
mBack->Surf()->ProducerAcquire();
return true;
}
UniquePtr<ReadBuffer> GLScreenBuffer::CreateRead(SharedSurface* surf) {
GLContext* gl = mFactory->mGL;
const GLFormats& formats = mFactory->mFormats;
const SurfaceCaps& caps = mFactory->ReadCaps();
return ReadBuffer::Create(gl, caps, formats, surf);
}
////////////////////////////////////////////////////////////////////////
// Utils
static void CreateRenderbuffersForOffscreen(GLContext* const aGL,
const GLFormats& aFormats,
const gfx::IntSize& aSize,
GLuint* const aDepthRB,
GLuint* const aStencilRB) {
const auto fnCreateRenderbuffer = [&](const GLenum sizedFormat) {
GLuint rb = 0;
aGL->fGenRenderbuffers(1, &rb);
ScopedBindRenderbuffer autoRB(aGL, rb);
aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, sizedFormat, aSize.width,
aSize.height);
return rb;
};
if (aDepthRB && aStencilRB && aFormats.depthStencil) {
*aDepthRB = fnCreateRenderbuffer(aFormats.depthStencil);
*aStencilRB = *aDepthRB;
} else {
if (aDepthRB) {
MOZ_ASSERT(aFormats.depth);
*aDepthRB = fnCreateRenderbuffer(aFormats.depth);
}
if (aStencilRB) {
MOZ_ASSERT(aFormats.stencil);
*aStencilRB = fnCreateRenderbuffer(aFormats.stencil);
}
}
}
////////////////////////////////////////////////////////////////////////
// ReadBuffer
UniquePtr<ReadBuffer> ReadBuffer::Create(GLContext* gl, const SurfaceCaps& caps,
const GLFormats& formats,
SharedSurface* surf) {
MOZ_ASSERT(surf);
if (surf->mAttachType == AttachmentType::Screen) {
// Don't need anything. Our read buffer will be the 'screen'.
return UniquePtr<ReadBuffer>(new ReadBuffer(gl, 0, 0, 0, surf));
}
GLuint depthRB = 0;
GLuint stencilRB = 0;
GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
GLContext::LocalErrorScope localError(*gl);
CreateRenderbuffersForOffscreen(gl, formats, surf->mSize, pDepthRB,
pStencilRB);
GLuint colorTex = 0;
GLuint colorRB = 0;
GLenum target = 0;
switch (surf->mAttachType) {
case AttachmentType::GLTexture:
colorTex = surf->ProdTexture();
target = surf->ProdTextureTarget();
break;
case AttachmentType::GLRenderbuffer:
colorRB = surf->ProdRenderbuffer();
break;
default:
MOZ_CRASH("GFX: Unknown attachment type, create?");
}
MOZ_ASSERT(colorTex || colorRB);
GLuint fb = 0;
gl->fGenFramebuffers(1, &fb);
gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb, target);
gl->mFBOMapping[fb] = surf;
UniquePtr<ReadBuffer> ret(new ReadBuffer(gl, fb, depthRB, stencilRB, surf));
GLenum err = localError.GetError();
MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
if (err) return nullptr;
const bool needsAcquire = !surf->IsProducerAcquired();
if (needsAcquire) {
surf->ProducerReadAcquire();
}
const bool isComplete = gl->IsFramebufferComplete(fb);
if (needsAcquire) {
surf->ProducerReadRelease();
}
if (!isComplete) return nullptr;
return ret;
}
ReadBuffer::~ReadBuffer() {
if (!mGL->MakeCurrent()) return;
GLuint fb = mFB;
GLuint rbs[] = {
mDepthRB,
(mStencilRB != mDepthRB) ? mStencilRB
: 0, // Don't double-delete DEPTH_STENCIL RBs.
};
mGL->fDeleteFramebuffers(1, &fb);
mGL->fDeleteRenderbuffers(2, rbs);
mGL->mFBOMapping.erase(mFB);
}
void ReadBuffer::Attach(SharedSurface* surf) {
MOZ_ASSERT(surf && mSurf);
MOZ_ASSERT(surf->mAttachType == mSurf->mAttachType);
MOZ_ASSERT(surf->mSize == mSurf->mSize);
// Nothing else is needed for AttachType Screen.
if (surf->mAttachType != AttachmentType::Screen) {
GLuint colorTex = 0;
GLuint colorRB = 0;
GLenum target = 0;
switch (surf->mAttachType) {
case AttachmentType::GLTexture:
colorTex = surf->ProdTexture();
target = surf->ProdTextureTarget();
break;
case AttachmentType::GLRenderbuffer:
colorRB = surf->ProdRenderbuffer();
break;
default:
MOZ_CRASH("GFX: Unknown attachment type, attach?");
}
mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB, target);
mGL->mFBOMapping[mFB] = surf;
MOZ_GL_ASSERT(mGL, mGL->IsFramebufferComplete(mFB));
}
mSurf = surf;
}
const gfx::IntSize& ReadBuffer::Size() const { return mSurf->mSize; }
} // namespace mozilla::gl

Просмотреть файл

@ -20,49 +20,179 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/UniquePtr.h"
#include "SharedSurface.h"
#include "SurfaceTypes.h"
namespace mozilla {
namespace layers {
class KnowsCompositor;
class LayersIPCChannel;
class SharedSurfaceTextureClient;
enum class LayersBackend : int8_t;
} // namespace layers
namespace gl {
class GLContext;
class SharedSurface;
class ShSurfHandle;
class SurfaceFactory;
class SwapChain;
class SwapChainPresenter final {
friend class SwapChain;
class ReadBuffer {
public:
// Infallible, always non-null.
static UniquePtr<ReadBuffer> Create(GLContext* gl, const SurfaceCaps& caps,
const GLFormats& formats,
SharedSurface* surf);
SwapChain* mSwapChain;
UniquePtr<SharedSurface> mBackBuffer;
protected:
GLContext* const mGL;
public:
explicit SwapChainPresenter(SwapChain& swapChain);
~SwapChainPresenter();
const GLuint mFB;
const auto& BackBuffer() const { return mBackBuffer; }
protected:
// mFB has the following attachments:
const GLuint mDepthRB;
const GLuint mStencilRB;
// note no mColorRB here: this is provided by mSurf.
SharedSurface* mSurf;
UniquePtr<SharedSurface> SwapBackBuffer(UniquePtr<SharedSurface>);
GLuint Fb() const;
ReadBuffer(GLContext* gl, GLuint fb, GLuint depthRB, GLuint stencilRB,
SharedSurface* surf)
: mGL(gl),
mFB(fb),
mDepthRB(depthRB),
mStencilRB(stencilRB),
mSurf(surf) {}
public:
virtual ~ReadBuffer();
// Cannot attach a surf of a different AttachType or Size than before.
void Attach(SharedSurface* surf);
const gfx::IntSize& Size() const;
SharedSurface* SharedSurf() const { return mSurf; }
};
// -
class SwapChain final {
friend class SwapChainPresenter;
class GLScreenBuffer final {
public:
UniquePtr<SurfaceFactory> mFactory;
// Infallible.
static UniquePtr<GLScreenBuffer> Create(GLContext* gl,
const gfx::IntSize& size,
const SurfaceCaps& caps);
static UniquePtr<SurfaceFactory> CreateFactory(
GLContext* gl, const SurfaceCaps& caps,
layers::KnowsCompositor* compositorConnection,
const layers::TextureFlags& flags);
static UniquePtr<SurfaceFactory> CreateFactory(
GLContext* gl, const SurfaceCaps& caps,
layers::LayersIPCChannel* ipcChannel, layers::LayersBackend backend,
bool useANGLE, const layers::TextureFlags& flags);
private:
UniquePtr<SharedSurface> mFrontBuffer;
SwapChainPresenter* mPresenter = nullptr;
GLContext* const mGL; // Owns us.
public:
const SurfaceCaps mCaps;
private:
UniquePtr<SurfaceFactory> mFactory;
RefPtr<layers::SharedSurfaceTextureClient> mBack;
RefPtr<layers::SharedSurfaceTextureClient> mFront;
UniquePtr<ReadBuffer> mRead;
// Below are the parts that help us pretend to be framebuffer 0:
GLuint mUserDrawFB;
GLuint mUserReadFB;
GLuint mInternalDrawFB;
GLuint mInternalReadFB;
#ifdef DEBUG
bool mInInternalMode_DrawFB;
bool mInInternalMode_ReadFB;
#endif
GLScreenBuffer(GLContext* gl, const SurfaceCaps& caps,
UniquePtr<SurfaceFactory> factory);
public:
SwapChain();
virtual ~SwapChain();
virtual ~GLScreenBuffer();
const auto& FrontBuffer() const { return mFrontBuffer; }
UniquePtr<SwapChainPresenter> Acquire(const gfx::IntSize&);
const auto& Factory() const { return mFactory; }
const auto& Front() const { return mFront; }
SharedSurface* SharedSurf() const {
MOZ_ASSERT(mRead);
return mRead->SharedSurf();
}
private:
GLuint DrawFB() const { return ReadFB(); }
GLuint ReadFB() const { return mRead->mFB; }
public:
void DeletingFB(GLuint fb);
const gfx::IntSize& Size() const {
MOZ_ASSERT(mRead);
return mRead->Size();
}
bool IsReadBufferReady() const { return mRead.get() != nullptr; }
bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border);
/**
* Attempts to read pixels from the current bound framebuffer, if
* it is backed by a SharedSurface.
*
* Returns true if the pixel data has been read back, false
* otherwise.
*/
bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid* pixels);
// Morph changes the factory used to create surfaces.
void Morph(UniquePtr<SurfaceFactory> newFactory);
private:
// Returns false on error or inability to resize.
bool Swap(const gfx::IntSize& size);
public:
bool PublishFrame(const gfx::IntSize& size) { return Swap(size); }
bool Resize(const gfx::IntSize& size);
private:
bool Attach(SharedSurface* surf, const gfx::IntSize& size);
UniquePtr<ReadBuffer> CreateRead(SharedSurface* surf);
public:
/* `fb` in these functions is the framebuffer the GLContext is hoping to
* bind. When this is 0, we intercept the call and bind our own
* framebuffers. As a client of these functions, just bind 0 when you want
* to draw to the default framebuffer/'screen'.
*/
void BindFB(GLuint fb);
void BindDrawFB(GLuint fb);
void BindReadFB(GLuint fb);
GLuint GetFB() const;
GLuint GetDrawFB() const;
GLuint GetReadFB() const;
// Here `fb` is the actual framebuffer you want bound. Binding 0 will
// bind the (generally useless) default framebuffer.
void BindReadFB_Internal(GLuint fb);
};
} // namespace gl

Просмотреть файл

@ -13,52 +13,212 @@
#include "nsThreadUtils.h"
#include "ScopedGLHelpers.h"
#include "SharedSurfaceGL.h"
#include "SharedSurfaceEGL.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "mozilla/layers/TextureForwarder.h"
#include "mozilla/StaticPrefs_webgl.h"
#include "mozilla/Unused.h"
#include "VRManagerChild.h"
#ifdef XP_WIN
# include "SharedSurfaceANGLE.h"
# include "SharedSurfaceD3D11Interop.h"
#endif
#ifdef XP_MACOSX
# include "SharedSurfaceIO.h"
#endif
#ifdef MOZ_X11
# include "GLXLibrary.h"
# include "SharedSurfaceGLX.h"
#endif
#ifdef MOZ_WAYLAND
# include "gfxPlatformGtk.h"
# include "SharedSurfaceDMABUF.h"
#endif
namespace mozilla {
namespace gl {
/*static*/
bool SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
SurfaceFactory* factory) {
GLContext* gl = src->mGL;
// If `src` begins locked, it must end locked, though we may
// temporarily unlock it if we need to.
MOZ_ASSERT((src == gl->GetLockedSurface()) == src->IsLocked());
gl->MakeCurrent();
if (src->mAttachType == AttachmentType::Screen &&
dest->mAttachType == AttachmentType::Screen) {
// Here, we actually need to blit through a temp surface, so let's make one.
UniquePtr<SharedSurface_Basic> tempSurf;
tempSurf = SharedSurface_Basic::Create(gl, factory->mFormats, src->mSize,
factory->mCaps.alpha);
if (!tempSurf) {
gfxCriticalNote << "Failed to allocate SharedSurface_Basic.";
return false;
}
ProdCopy(src, tempSurf.get(), factory);
ProdCopy(tempSurf.get(), dest, factory);
return true;
}
if (src->mAttachType == AttachmentType::Screen) {
SharedSurface* origLocked = gl->GetLockedSurface();
bool srcNeedsUnlock = false;
bool origNeedsRelock = false;
if (origLocked != src) {
if (origLocked) {
origLocked->UnlockProd();
origNeedsRelock = true;
}
src->LockProd();
srcNeedsUnlock = true;
}
if (dest->mAttachType == AttachmentType::GLTexture) {
GLuint destTex = dest->ProdTexture();
GLenum destTarget = dest->ProdTextureTarget();
const ScopedBindFramebuffer bindFB(gl, 0);
gl->BlitHelper()->BlitFramebufferToTexture(destTex, src->mSize,
dest->mSize, destTarget);
} else if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
gl->BlitHelper()->BlitFramebufferToFramebuffer(
0, destWrapper.FB(), gfx::IntRect({}, src->mSize),
gfx::IntRect({}, dest->mSize));
} else {
MOZ_CRASH("GFX: Unhandled dest->mAttachType 1.");
}
if (srcNeedsUnlock) src->UnlockProd();
if (origNeedsRelock) origLocked->LockProd();
return true;
}
if (dest->mAttachType == AttachmentType::Screen) {
SharedSurface* origLocked = gl->GetLockedSurface();
bool destNeedsUnlock = false;
bool origNeedsRelock = false;
if (origLocked != dest) {
if (origLocked) {
origLocked->UnlockProd();
origNeedsRelock = true;
}
dest->LockProd();
destNeedsUnlock = true;
}
if (src->mAttachType == AttachmentType::GLTexture) {
GLuint srcTex = src->ProdTexture();
GLenum srcTarget = src->ProdTextureTarget();
const ScopedBindFramebuffer bindFB(gl, 0);
gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, src->mSize,
dest->mSize, srcTarget);
} else if (src->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint srcRB = src->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
gl->BlitHelper()->BlitFramebufferToFramebuffer(
srcWrapper.FB(), 0, gfx::IntRect({}, src->mSize),
gfx::IntRect({}, dest->mSize));
} else {
MOZ_CRASH("GFX: Unhandled src->mAttachType 2.");
}
if (destNeedsUnlock) dest->UnlockProd();
if (origNeedsRelock) origLocked->LockProd();
return true;
}
// Alright, done with cases involving Screen types.
// Only {src,dest}x{texture,renderbuffer} left.
if (src->mAttachType == AttachmentType::GLTexture) {
GLuint srcTex = src->ProdTexture();
GLenum srcTarget = src->ProdTextureTarget();
if (dest->mAttachType == AttachmentType::GLTexture) {
GLuint destTex = dest->ProdTexture();
GLenum destTarget = dest->ProdTextureTarget();
gl->BlitHelper()->BlitTextureToTexture(
srcTex, destTex, src->mSize, dest->mSize, srcTarget, destTarget);
return true;
}
if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
const ScopedBindFramebuffer bindFB(gl, destWrapper.FB());
gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, src->mSize,
dest->mSize, srcTarget);
return true;
}
MOZ_CRASH("GFX: Unhandled dest->mAttachType 3.");
}
if (src->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint srcRB = src->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
if (dest->mAttachType == AttachmentType::GLTexture) {
GLuint destTex = dest->ProdTexture();
GLenum destTarget = dest->ProdTextureTarget();
const ScopedBindFramebuffer bindFB(gl, srcWrapper.FB());
gl->BlitHelper()->BlitFramebufferToTexture(destTex, src->mSize,
dest->mSize, destTarget);
return true;
}
if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
GLuint destRB = dest->ProdRenderbuffer();
ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
gl->BlitHelper()->BlitFramebufferToFramebuffer(
srcWrapper.FB(), destWrapper.FB(), gfx::IntRect({}, src->mSize),
gfx::IntRect({}, dest->mSize));
return true;
}
MOZ_CRASH("GFX: Unhandled dest->mAttachType 4.");
}
MOZ_CRASH("GFX: Unhandled src->mAttachType 5.");
}
////////////////////////////////////////////////////////////////////////
// SharedSurface
SharedSurface::SharedSurface(const SharedSurfaceDesc& desc,
UniquePtr<MozFramebuffer> fb)
: mDesc(desc), mFb(std::move(fb)) {}
SharedSurface::SharedSurface(SharedSurfaceType type, AttachmentType attachType,
GLContext* gl, const gfx::IntSize& size,
bool hasAlpha, bool canRecycle)
: mType(type),
mAttachType(attachType),
mGL(gl),
mSize(size),
mHasAlpha(hasAlpha),
mCanRecycle(canRecycle),
mIsLocked(false),
mIsProducerAcquired(false) {}
SharedSurface::~SharedSurface() = default;
layers::TextureFlags SharedSurface::GetTextureFlags() const {
return layers::TextureFlags::NO_FLAGS;
}
void SharedSurface::LockProd() {
MOZ_ASSERT(!mIsLocked);
LockProdImpl();
mDesc.gl->LockSurface(this);
mGL->LockSurface(this);
mIsLocked = true;
}
@ -67,84 +227,325 @@ void SharedSurface::UnlockProd() {
UnlockProdImpl();
mDesc.gl->UnlockSurface(this);
mGL->UnlockSurface(this);
mIsLocked = false;
}
////////////////////////////////////////////////////////////////////////
// SurfaceFactory
/* static */
UniquePtr<SurfaceFactory> SurfaceFactory::Create(
GLContext* const pGl, const layers::TextureType consumerType) {
auto& gl = *pGl;
switch (consumerType) {
case layers::TextureType::D3D11:
#ifdef XP_WIN
if (gl.IsANGLE()) {
return SurfaceFactory_ANGLEShareHandle::Create(gl);
}
if (StaticPrefs::webgl_dxgl_enabled()) {
return SurfaceFactory_D3D11Interop::Create(gl);
}
#endif
return nullptr;
static void ChooseBufferBits(const SurfaceCaps& caps,
SurfaceCaps* const out_drawCaps,
SurfaceCaps* const out_readCaps) {
MOZ_ASSERT(out_drawCaps);
MOZ_ASSERT(out_readCaps);
case layers::TextureType::MacIOSurface:
#ifdef XP_MACOSX
return MakeUnique<SurfaceFactory_IOSurface>(gl);
#else
return nullptr;
#endif
SurfaceCaps screenCaps;
case layers::TextureType::X11:
#ifdef MOZ_X11
if (gl.GetContextType() != GLContextType::GLX) return nullptr;
if (!sGLXLibrary.UseTextureFromPixmap()) return nullptr;
return MakeUnique<SurfaceFactory_GLXDrawable>(gl);
#else
return nullptr;
#endif
screenCaps.color = caps.color;
screenCaps.alpha = caps.alpha;
screenCaps.bpp16 = caps.bpp16;
case layers::TextureType::WaylandDMABUF:
#ifdef MOZ_WAYLAND
if (gl.GetContextType() != GLContextType::EGL) return nullptr;
if (!gfxPlatformGtk::GetPlatform()->UseWaylandDMABufWebGL())
return nullptr;
return MakeUnique<SurfaceFactory_DMABUF>(gl);
#else
return nullptr;
#endif
screenCaps.depth = caps.depth;
screenCaps.stencil = caps.stencil;
case layers::TextureType::AndroidNativeWindow:
#ifdef MOZ_WIDGET_ANDROID
if (XRE_IsParentProcess() && !StaticPrefs::webgl_enable_surface_texture())
return nullptr;
return MakeUnique<SurfaceFactory_SurfaceTexture>(gl);
#else
return nullptr;
#endif
screenCaps.preserve = caps.preserve;
case layers::TextureType::EGLImage:
#ifdef MOZ_WIDGET_ANDROID
if (XRE_IsParentProcess()) {
return SurfaceFactory_EGLImage::Create(gl);
}
#endif
return nullptr;
case layers::TextureType::Unknown:
case layers::TextureType::DIB:
case layers::TextureType::Last:
break;
}
return nullptr;
out_drawCaps->Clear();
*out_readCaps = screenCaps;
}
SurfaceFactory::SurfaceFactory(const PartialSharedSurfaceDesc& partialDesc)
: mDesc(partialDesc), mMutex("SurfaceFactor::mMutex") {}
SurfaceFactory::SurfaceFactory(
SharedSurfaceType type, GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags)
: mType(type),
mGL(gl),
mCaps(caps),
mAllocator(allocator),
mFlags(flags),
mFormats(gl->ChooseGLFormats(caps)),
mMutex("SurfaceFactor::mMutex") {
ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps);
}
SurfaceFactory::~SurfaceFactory() = default;
SurfaceFactory::~SurfaceFactory() {
while (!mRecycleTotalPool.empty()) {
RefPtr<layers::SharedSurfaceTextureClient> tex = *mRecycleTotalPool.begin();
StopRecycling(tex);
}
MOZ_RELEASE_ASSERT(mRecycleTotalPool.empty(),
"GFX: Surface recycle pool not empty.");
// If we mRecycleFreePool.clear() before StopRecycling(), we may try to
// recycle it, fail, call StopRecycling(), then return here and call it again.
mRecycleFreePool.clear();
}
already_AddRefed<layers::SharedSurfaceTextureClient>
SurfaceFactory::NewTexClient(const gfx::IntSize& size) {
while (!mRecycleFreePool.empty()) {
RefPtr<layers::SharedSurfaceTextureClient> cur = mRecycleFreePool.front();
mRecycleFreePool.pop();
if (cur->Surf()->mSize == size) {
cur->Surf()->WaitForBufferOwnership();
return cur.forget();
}
StopRecycling(cur);
}
UniquePtr<SharedSurface> surf = CreateShared(size);
if (!surf) return nullptr;
RefPtr<layers::SharedSurfaceTextureClient> ret;
ret = layers::SharedSurfaceTextureClient::Create(std::move(surf), this,
mAllocator, mFlags);
StartRecycling(ret);
return ret.forget();
}
void SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc) {
tc->SetRecycleCallback(&SurfaceFactory::RecycleCallback,
static_cast<void*>(this));
bool didInsert = mRecycleTotalPool.insert(tc);
MOZ_RELEASE_ASSERT(
didInsert,
"GFX: Shared surface texture client was not inserted to recycle.");
mozilla::Unused << didInsert;
}
void SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc) {
MutexAutoLock autoLock(mMutex);
// Must clear before releasing ref.
tc->ClearRecycleCallback();
bool didErase = mRecycleTotalPool.erase(tc);
MOZ_RELEASE_ASSERT(didErase,
"GFX: Shared texture surface client was not erased.");
mozilla::Unused << didErase;
}
/*static*/
void SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC,
void* rawFactory) {
RefPtr<layers::SharedSurfaceTextureClient> tc;
tc = static_cast<layers::SharedSurfaceTextureClient*>(rawTC);
SurfaceFactory* factory = static_cast<SurfaceFactory*>(rawFactory);
if (tc->Surf()->mCanRecycle) {
if (factory->Recycle(tc)) return;
}
// Did not recover the tex client. End the (re)cycle!
factory->StopRecycling(tc);
}
bool SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient) {
MOZ_ASSERT(texClient);
MutexAutoLock autoLock(mMutex);
if (mRecycleFreePool.size() >= 2) {
return false;
}
RefPtr<layers::SharedSurfaceTextureClient> texClientRef = texClient;
mRecycleFreePool.push(texClientRef);
return true;
}
////////////////////////////////////////////////////////////////////////////////
// ScopedReadbackFB
ScopedReadbackFB::ScopedReadbackFB(SharedSurface* src)
: mGL(src->mGL), mAutoFB(mGL) {
switch (src->mAttachType) {
case AttachmentType::GLRenderbuffer: {
mGL->fGenFramebuffers(1, &mTempFB);
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
GLuint rb = src->ProdRenderbuffer();
mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, rb);
break;
}
case AttachmentType::GLTexture: {
mGL->fGenFramebuffers(1, &mTempFB);
mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
GLuint tex = src->ProdTexture();
GLenum texImageTarget = src->ProdTextureTarget();
mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0, texImageTarget,
tex, 0);
break;
}
case AttachmentType::Screen: {
SharedSurface* origLocked = mGL->GetLockedSurface();
if (origLocked != src) {
if (origLocked) {
mSurfToLock = origLocked;
mSurfToLock->UnlockProd();
}
mSurfToUnlock = src;
mSurfToUnlock->LockProd();
}
// TODO: This should just be BindFB, but we don't have
// the patch for this yet. (bug 1045955)
MOZ_ASSERT(mGL->Screen());
mGL->Screen()->BindReadFB_Internal(0);
break;
}
default:
MOZ_CRASH("GFX: Unhandled `mAttachType`.");
}
if (src->NeedsIndirectReads()) {
mGL->fGenTextures(1, &mTempTex);
{
ScopedBindTexture autoTex(mGL, mTempTex);
GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
auto width = src->mSize.width;
auto height = src->mSize.height;
mGL->fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width, height,
0);
}
mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_TEXTURE_2D, mTempTex, 0);
}
}
ScopedReadbackFB::~ScopedReadbackFB() {
if (mTempFB) {
mGL->fDeleteFramebuffers(1, &mTempFB);
}
if (mTempTex) {
mGL->fDeleteTextures(1, &mTempTex);
}
if (mSurfToUnlock) {
mSurfToUnlock->UnlockProd();
}
if (mSurfToLock) {
mSurfToLock->LockProd();
}
}
////////////////////////////////////////////////////////////////////////////////
class AutoLockBits {
gfx::DrawTarget* mDT;
uint8_t* mLockedBits;
public:
explicit AutoLockBits(gfx::DrawTarget* dt) : mDT(dt), mLockedBits(nullptr) {
MOZ_ASSERT(mDT);
}
bool Lock(uint8_t** data, gfx::IntSize* size, int32_t* stride,
gfx::SurfaceFormat* format) {
if (!mDT->LockBits(data, size, stride, format)) return false;
mLockedBits = *data;
return true;
}
~AutoLockBits() {
if (mLockedBits) mDT->ReleaseBits(mLockedBits);
}
};
bool ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst) {
AutoLockBits lock(dst);
uint8_t* dstBytes;
gfx::IntSize dstSize;
int32_t dstStride;
gfx::SurfaceFormat dstFormat;
if (!lock.Lock(&dstBytes, &dstSize, &dstStride, &dstFormat)) return false;
const bool isDstRGBA = (dstFormat == gfx::SurfaceFormat::R8G8B8A8 ||
dstFormat == gfx::SurfaceFormat::R8G8B8X8);
MOZ_ASSERT_IF(!isDstRGBA, dstFormat == gfx::SurfaceFormat::B8G8R8A8 ||
dstFormat == gfx::SurfaceFormat::B8G8R8X8);
size_t width = src->mSize.width;
size_t height = src->mSize.height;
MOZ_ASSERT(width == (size_t)dstSize.width);
MOZ_ASSERT(height == (size_t)dstSize.height);
GLenum readGLFormat;
GLenum readType;
{
ScopedReadbackFB autoReadback(src);
// We have a source FB, now we need a format.
GLenum dstGLFormat = isDstRGBA ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
GLenum dstType = LOCAL_GL_UNSIGNED_BYTE;
// We actually don't care if they match, since we can handle
// any read{Format,Type} we get.
GLContext* gl = src->mGL;
GetActualReadFormats(gl, dstGLFormat, dstType, &readGLFormat, &readType);
MOZ_ASSERT(readGLFormat == LOCAL_GL_RGBA || readGLFormat == LOCAL_GL_BGRA);
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
// ReadPixels from the current FB into lockedBits.
{
ScopedPackState scopedPackState(gl);
bool handled = scopedPackState.SetForWidthAndStrideRGBA(width, dstStride);
MOZ_RELEASE_ASSERT(handled, "Unhandled stride");
gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType,
dstBytes);
}
}
const bool isReadRGBA = readGLFormat == LOCAL_GL_RGBA;
if (isReadRGBA != isDstRGBA) {
for (size_t j = 0; j < height; ++j) {
uint8_t* rowItr = dstBytes + j * dstStride;
uint8_t* rowEnd = rowItr + 4 * width;
while (rowItr != rowEnd) {
std::swap(rowItr[0], rowItr[2]);
rowItr += 4;
}
}
}
return true;
}
uint32_t ReadPixel(SharedSurface* src) {
GLContext* gl = src->mGL;
uint32_t pixel;
ScopedReadbackFB a(src);
{
ScopedPackState scopedPackState(gl);
UniquePtr<uint8_t[]> bytes(new uint8_t[4]);
gl->raw_fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
bytes.get());
memcpy(&pixel, bytes.get(), 4);
}
return pixel;
}
} // namespace gl
} // namespace mozilla
} /* namespace mozilla */

Просмотреть файл

@ -19,7 +19,6 @@
#include <set>
#include <stdint.h>
#include "GLContext.h" // Bug 1635644
#include "GLContextTypes.h"
#include "GLDefs.h"
#include "mozilla/Attributes.h"
@ -28,6 +27,7 @@
#include "mozilla/Mutex.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "ScopedGLHelpers.h"
#include "SurfaceTypes.h"
class nsIThread;
@ -39,46 +39,46 @@ class DrawTarget;
} // namespace gfx
namespace layers {
class KnowsCompositor;
enum class LayersBackend : int8_t;
class LayersIPCChannel;
class SharedSurfaceTextureClient;
enum class TextureFlags : uint32_t;
class SurfaceDescriptor;
class TextureClient;
enum class TextureFlags : uint32_t;
enum class TextureType : int8_t;
} // namespace layers
namespace gl {
class MozFramebuffer;
struct ScopedBindFramebuffer;
class GLContext;
class SurfaceFactory;
struct PartialSharedSurfaceDesc {
const WeakPtr<GLContext> gl;
const SharedSurfaceType type;
const layers::TextureType consumerType;
const bool canRecycle;
};
struct SharedSurfaceDesc : public PartialSharedSurfaceDesc {
gfx::IntSize size = {};
};
class ShSurfHandle;
class SharedSurface {
public:
const SharedSurfaceDesc mDesc;
const UniquePtr<MozFramebuffer> mFb; // null if we should use fb=0.
static bool ProdCopy(SharedSurface* src, SharedSurface* dest,
SurfaceFactory* factory);
const SharedSurfaceType mType;
const AttachmentType mAttachType;
const WeakPtr<GLContext> mGL;
const gfx::IntSize mSize;
const bool mHasAlpha;
const bool mCanRecycle;
protected:
bool mIsLocked = false;
bool mIsProducerAcquired = false;
bool mIsLocked;
bool mIsProducerAcquired;
SharedSurface(const SharedSurfaceDesc&, UniquePtr<MozFramebuffer>);
SharedSurface(SharedSurfaceType type, AttachmentType attachType,
GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
bool canRecycle);
public:
virtual ~SharedSurface();
// Specifies to the TextureClient any flags which
// are required by the SharedSurface backend.
virtual layers::TextureFlags GetTextureFlags() const;
bool IsLocked() const { return mIsLocked; }
bool IsProducerAcquired() const { return mIsProducerAcquired; }
@ -94,12 +94,11 @@ class SharedSurface {
virtual void Commit() {}
protected:
virtual void LockProdImpl(){};
virtual void UnlockProdImpl(){};
virtual void ProducerAcquireImpl(){};
virtual void ProducerReleaseImpl(){};
virtual void LockProdImpl() = 0;
virtual void UnlockProdImpl() = 0;
virtual void ProducerAcquireImpl() = 0;
virtual void ProducerReleaseImpl() = 0;
virtual void ProducerReadAcquireImpl() { ProducerAcquireImpl(); }
virtual void ProducerReadReleaseImpl() { ProducerReleaseImpl(); }
@ -134,47 +133,176 @@ class SharedSurface {
// You can call WaitForBufferOwnership to wait for availability.
virtual bool IsBufferAvailable() const { return true; }
// For use when AttachType is correct.
virtual GLenum ProdTextureTarget() const {
MOZ_ASSERT(mAttachType == AttachmentType::GLTexture);
return LOCAL_GL_TEXTURE_2D;
}
virtual GLuint ProdTexture() {
MOZ_ASSERT(mAttachType == AttachmentType::GLTexture);
MOZ_CRASH("GFX: Did you forget to override this function?");
}
virtual GLuint ProdRenderbuffer() {
MOZ_ASSERT(mAttachType == AttachmentType::GLRenderbuffer);
MOZ_CRASH("GFX: Did you forget to override this function?");
}
virtual bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border) {
return false;
}
virtual bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid* pixels) {
return false;
}
virtual bool NeedsIndirectReads() const { return false; }
virtual Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() = 0;
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) = 0;
virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) {
return false;
}
};
// -
class SurfaceFactory {
public:
const PartialSharedSurfaceDesc mDesc;
protected:
Mutex mMutex;
template <typename T>
class RefSet {
std::set<T*> mSet;
public:
static UniquePtr<SurfaceFactory> Create(GLContext*, layers::TextureType);
~RefSet() { clear(); }
protected:
explicit SurfaceFactory(const PartialSharedSurfaceDesc&);
auto begin() -> decltype(mSet.begin()) { return mSet.begin(); }
public:
virtual ~SurfaceFactory();
void clear() {
for (auto itr = mSet.begin(); itr != mSet.end(); ++itr) {
(*itr)->Release();
}
mSet.clear();
}
protected:
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc&) = 0;
bool empty() const { return mSet.empty(); }
public:
UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) {
return CreateSharedImpl({mDesc, size});
bool insert(T* x) {
if (mSet.insert(x).second) {
x->AddRef();
return true;
}
return false;
}
bool erase(T* x) {
if (mSet.erase(x)) {
x->Release();
return true;
}
return false;
}
};
template <typename T>
inline UniquePtr<T> AsUnique(T* const p) {
return UniquePtr<T>(p);
}
class RefQueue {
std::queue<T*> mQueue;
public:
~RefQueue() { clear(); }
void clear() {
while (!empty()) {
pop();
}
}
bool empty() const { return mQueue.empty(); }
size_t size() const { return mQueue.size(); }
void push(T* x) {
mQueue.push(x);
x->AddRef();
}
T* front() const { return mQueue.front(); }
void pop() {
T* x = mQueue.front();
x->Release();
mQueue.pop();
}
};
class SurfaceFactory : public SupportsWeakPtr<SurfaceFactory> {
public:
// Should use the VIRTUAL version, but it's currently incompatible
// with SupportsWeakPtr. (bug 1049278)
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SurfaceFactory)
const SharedSurfaceType mType;
GLContext* const mGL;
const SurfaceCaps mCaps;
const RefPtr<layers::LayersIPCChannel> mAllocator;
const layers::TextureFlags mFlags;
const GLFormats mFormats;
Mutex mMutex;
protected:
SurfaceCaps mDrawCaps;
SurfaceCaps mReadCaps;
RefQueue<layers::SharedSurfaceTextureClient> mRecycleFreePool;
RefSet<layers::SharedSurfaceTextureClient> mRecycleTotalPool;
SurfaceFactory(SharedSurfaceType type, GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags);
public:
virtual ~SurfaceFactory();
const SurfaceCaps& DrawCaps() const { return mDrawCaps; }
const SurfaceCaps& ReadCaps() const { return mReadCaps; }
protected:
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) = 0;
void StartRecycling(layers::SharedSurfaceTextureClient* tc);
void SetRecycleCallback(layers::SharedSurfaceTextureClient* tc);
void StopRecycling(layers::SharedSurfaceTextureClient* tc);
public:
UniquePtr<SharedSurface> NewSharedSurface(const gfx::IntSize& size);
// already_AddRefed<ShSurfHandle> NewShSurfHandle(const gfx::IntSize& size);
already_AddRefed<layers::SharedSurfaceTextureClient> NewTexClient(
const gfx::IntSize& size);
static void RecycleCallback(layers::TextureClient* tc, void* /*closure*/);
// Auto-deletes surfs of the wrong type.
bool Recycle(layers::SharedSurfaceTextureClient* texClient);
};
class ScopedReadbackFB final {
GLContext* const mGL;
ScopedBindFramebuffer mAutoFB;
GLuint mTempFB = 0;
GLuint mTempTex = 0;
SharedSurface* mSurfToUnlock = nullptr;
SharedSurface* mSurfToLock = nullptr;
public:
explicit ScopedReadbackFB(SharedSurface* src);
~ScopedReadbackFB();
};
bool ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst);
uint32_t ReadPixel(SharedSurface* src);
} // namespace gl
} // namespace mozilla

Просмотреть файл

@ -18,8 +18,11 @@ namespace gl {
static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, EGLDisplay display,
EGLConfig config,
const gfx::IntSize& size) {
const EGLint attribs[] = {LOCAL_EGL_WIDTH, size.width, LOCAL_EGL_HEIGHT,
size.height, LOCAL_EGL_NONE};
auto width = size.width;
auto height = size.height;
EGLint attribs[] = {LOCAL_EGL_WIDTH, width, LOCAL_EGL_HEIGHT, height,
LOCAL_EGL_NONE};
DebugOnly<EGLint> preCallErr = egl->fGetError();
MOZ_ASSERT(preCallErr == LOCAL_EGL_SUCCESS);
@ -36,18 +39,18 @@ static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, EGLDisplay display,
/*static*/
UniquePtr<SharedSurface_ANGLEShareHandle>
SharedSurface_ANGLEShareHandle::Create(const SharedSurfaceDesc& desc) {
const auto& gle = GLContextEGL::Cast(desc.gl);
SharedSurface_ANGLEShareHandle::Create(GLContext* gl, EGLConfig config,
const gfx::IntSize& size,
bool hasAlpha) {
const auto& gle = GLContextEGL::Cast(gl);
const auto& egl = gle->mEgl;
MOZ_ASSERT(egl);
MOZ_ASSERT(egl->IsExtensionSupported(
GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle));
const auto& config = gle->mConfig;
MOZ_ASSERT(config);
EGLDisplay display = egl->Display();
EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, desc.size);
EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size);
if (!pbuffer) return nullptr;
// Declare everything before 'goto's.
@ -77,25 +80,27 @@ SharedSurface_ANGLEShareHandle::Create(const SharedSurfaceDesc& desc) {
}
#endif
return AsUnique(new SharedSurface_ANGLEShareHandle(desc, egl, pbuffer,
shareHandle, keyedMutex));
typedef SharedSurface_ANGLEShareHandle ptrT;
UniquePtr<ptrT> ret(
new ptrT(gl, egl, size, hasAlpha, pbuffer, shareHandle, keyedMutex));
return ret;
}
EGLDisplay SharedSurface_ANGLEShareHandle::Display() const {
return mEGL->Display();
}
EGLDisplay SharedSurface_ANGLEShareHandle::Display() { return mEGL->Display(); }
SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(
const SharedSurfaceDesc& desc, GLLibraryEGL* egl, EGLSurface pbuffer,
HANDLE shareHandle, const RefPtr<IDXGIKeyedMutex>& keyedMutex)
: SharedSurface(desc, nullptr),
GLContext* gl, GLLibraryEGL* egl, const gfx::IntSize& size, bool hasAlpha,
EGLSurface pbuffer, HANDLE shareHandle,
const RefPtr<IDXGIKeyedMutex>& keyedMutex)
: SharedSurface(SharedSurfaceType::EGLSurfaceANGLE, AttachmentType::Screen,
gl, size, hasAlpha, true),
mEGL(egl),
mPBuffer(pbuffer),
mShareHandle(shareHandle),
mKeyedMutex(keyedMutex) {}
SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() {
const auto& gl = mDesc.gl;
GLContext* gl = mGL;
if (gl && GLContextEGL::Cast(gl)->GetEGLSurfaceOverride() == mPBuffer) {
GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(EGL_NO_SURFACE);
@ -104,8 +109,7 @@ SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() {
}
void SharedSurface_ANGLEShareHandle::LockProdImpl() {
const auto& gl = mDesc.gl;
GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(mPBuffer);
GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(mPBuffer);
}
void SharedSurface_ANGLEShareHandle::UnlockProdImpl() {}
@ -120,16 +124,15 @@ void SharedSurface_ANGLEShareHandle::ProducerAcquireImpl() {
}
void SharedSurface_ANGLEShareHandle::ProducerReleaseImpl() {
const auto& gl = mDesc.gl;
if (mKeyedMutex) {
// XXX: ReleaseSync() has an implicit flush of the D3D commands
// whether we need Flush() or not depends on the ANGLE semantics.
// For now, we'll just do it
gl->fFlush();
mGL->fFlush();
mKeyedMutex->ReleaseSync(0);
return;
}
gl->fFinish();
mGL->fFinish();
}
void SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl() {
@ -143,12 +146,14 @@ void SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl() {
}
}
Maybe<layers::SurfaceDescriptor>
SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor() {
const auto format = gfx::SurfaceFormat::B8G8R8A8;
return Some(layers::SurfaceDescriptorD3D10(
(WindowsHandle)mShareHandle, format, mDesc.size,
gfx::YUVColorSpace::UNKNOWN, gfx::ColorRange::FULL));
bool SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
gfx::SurfaceFormat format =
mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::B8G8R8X8;
*out_descriptor = layers::SurfaceDescriptorD3D10(
(WindowsHandle)mShareHandle, format, mSize, gfx::YUVColorSpace::UNKNOWN,
gfx::ColorRange::FULL);
return true;
}
class ScopedLockTexture final {
@ -299,29 +304,33 @@ bool SharedSurface_ANGLEShareHandle::ReadbackBySharedHandle(
/*static*/
UniquePtr<SurfaceFactory_ANGLEShareHandle>
SurfaceFactory_ANGLEShareHandle::Create(GLContext& gl) {
if (!gl.IsANGLE()) return nullptr;
const auto& gle = *GLContextEGL::Cast(&gl);
const auto& egl = gle.mEgl;
SurfaceFactory_ANGLEShareHandle::Create(
GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags) {
const auto& gle = GLContextEGL::Cast(gl);
const auto& egl = gle->mEgl;
if (!egl) return nullptr;
auto ext = GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle;
if (!egl->IsExtensionSupported(ext)) return nullptr;
if (XRE_IsContentProcess()) {
gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
}
const auto& config = gle->mConfig;
gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
MOZ_ASSERT(dm);
if (gl.IsWARP() != dm->IsWARP() || !dm->TextureSharingWorks()) {
return nullptr;
}
return AsUnique(new SurfaceFactory_ANGLEShareHandle(
{&gl, SharedSurfaceType::EGLSurfaceANGLE, layers::TextureType::D3D11,
true}));
typedef SurfaceFactory_ANGLEShareHandle ptrT;
UniquePtr<ptrT> ret(new ptrT(gl, caps, allocator, flags, egl, config));
return ret;
}
SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(
GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags, GLLibraryEGL* egl, EGLConfig config)
: SurfaceFactory(SharedSurfaceType::EGLSurfaceANGLE, gl, caps, allocator,
flags),
mProdGL(gl),
mEGL(egl),
mConfig(config) {}
} /* namespace gl */
} /* namespace mozilla */

Просмотреть файл

@ -18,22 +18,33 @@ namespace gl {
class GLContext;
class GLLibraryEGL;
class SharedSurface_ANGLEShareHandle final : public SharedSurface {
class SharedSurface_ANGLEShareHandle : public SharedSurface {
public:
static UniquePtr<SharedSurface_ANGLEShareHandle> Create(
GLContext* gl, EGLConfig config, const gfx::IntSize& size, bool hasAlpha);
static SharedSurface_ANGLEShareHandle* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::EGLSurfaceANGLE);
return (SharedSurface_ANGLEShareHandle*)surf;
}
protected:
GLLibraryEGL* const mEGL;
const EGLSurface mPBuffer;
public:
const HANDLE mShareHandle;
const RefPtr<IDXGIKeyedMutex> mKeyedMutex;
static UniquePtr<SharedSurface_ANGLEShareHandle> Create(
const SharedSurfaceDesc&);
protected:
RefPtr<IDXGIKeyedMutex> mKeyedMutex;
private:
SharedSurface_ANGLEShareHandle(const SharedSurfaceDesc&, GLLibraryEGL* egl,
SharedSurface_ANGLEShareHandle(GLContext* gl, GLLibraryEGL* egl,
const gfx::IntSize& size, bool hasAlpha,
EGLSurface pbuffer, HANDLE shareHandle,
const RefPtr<IDXGIKeyedMutex>& keyedMutex);
EGLDisplay Display() const;
EGLDisplay Display();
public:
virtual ~SharedSurface_ANGLEShareHandle();
@ -46,23 +57,36 @@ class SharedSurface_ANGLEShareHandle final : public SharedSurface {
virtual void ProducerReadAcquireImpl() override;
virtual void ProducerReadReleaseImpl() override;
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
virtual bool ReadbackBySharedHandle(
gfx::DataSourceSurface* out_surface) override;
};
class SurfaceFactory_ANGLEShareHandle final : public SurfaceFactory {
class SurfaceFactory_ANGLEShareHandle : public SurfaceFactory {
protected:
GLContext* const mProdGL;
GLLibraryEGL* const mEGL;
const EGLConfig mConfig;
public:
static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(GLContext& gl);
static UniquePtr<SurfaceFactory_ANGLEShareHandle> Create(
GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags);
private:
explicit SurfaceFactory_ANGLEShareHandle(const PartialSharedSurfaceDesc& desc)
: SurfaceFactory(desc) {}
protected:
SurfaceFactory_ANGLEShareHandle(
GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags, GLLibraryEGL* egl, EGLConfig config);
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override {
return SharedSurface_ANGLEShareHandle::Create(desc);
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_ANGLEShareHandle::Create(mProdGL, mConfig, size,
hasAlpha);
}
};

Просмотреть файл

@ -8,7 +8,6 @@
#include <d3d11.h>
#include <d3d11_1.h>
#include "GLContext.h"
#include "MozFramebuffer.h"
#include "WGLLibrary.h"
#include "nsPrintfCString.h"
#include "mozilla/gfx/DeviceManagerDx.h"
@ -310,34 +309,32 @@ class DXInterop2Device : public RefCounted<DXInterop2Device> {
/*static*/
UniquePtr<SharedSurface_D3D11Interop> SharedSurface_D3D11Interop::Create(
const SharedSurfaceDesc& desc, DXInterop2Device* interop) {
const auto& gl = desc.gl;
const auto& size = desc.size;
DXInterop2Device* interop, GLContext* gl, const gfx::IntSize& size,
bool hasAlpha) {
const auto& d3d = interop->mD3D;
auto data = Data{interop};
// Create a texture in case we need to readback.
const DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM;
CD3D11_TEXTURE2D_DESC texDesc(format, size.width, size.height, 1, 1);
texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
DXGI_FORMAT format =
hasAlpha ? DXGI_FORMAT_B8G8R8A8_UNORM : DXGI_FORMAT_B8G8R8X8_UNORM;
CD3D11_TEXTURE2D_DESC desc(format, size.width, size.height, 1, 1);
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
auto hr =
d3d->CreateTexture2D(&texDesc, nullptr, getter_AddRefs(data.texD3D));
RefPtr<ID3D11Texture2D> texD3D;
auto hr = d3d->CreateTexture2D(&desc, nullptr, getter_AddRefs(texD3D));
if (FAILED(hr)) {
NS_WARNING("Failed to create texture for CanvasLayer!");
return nullptr;
}
RefPtr<IDXGIResource> texDXGI;
hr = data.texD3D->QueryInterface(__uuidof(IDXGIResource),
getter_AddRefs(texDXGI));
hr = texD3D->QueryInterface(__uuidof(IDXGIResource), getter_AddRefs(texDXGI));
if (FAILED(hr)) {
NS_WARNING("Failed to open texture for sharing!");
return nullptr;
}
texDXGI->GetSharedHandle(&data.dxgiHandle);
HANDLE dxgiHandle;
texDXGI->GetSharedHandle(&dxgiHandle);
////
@ -346,25 +343,25 @@ UniquePtr<SharedSurface_D3D11Interop> SharedSurface_D3D11Interop::Create(
return nullptr;
}
data.interopRb = MakeUnique<Renderbuffer>(*gl);
data.lockHandle = interop->RegisterObject(data.texD3D, data.interopRb->name,
LOCAL_GL_RENDERBUFFER,
LOCAL_WGL_ACCESS_WRITE_DISCARD_NV);
if (!data.lockHandle) {
GLuint interopRB = 0;
gl->fGenRenderbuffers(1, &interopRB);
const auto lockHandle =
interop->RegisterObject(texD3D, interopRB, LOCAL_GL_RENDERBUFFER,
LOCAL_WGL_ACCESS_WRITE_DISCARD_NV);
if (!lockHandle) {
NS_WARNING("Failed to register D3D object with WGL.");
gl->fDeleteRenderbuffers(1, &interopRB);
return nullptr;
}
auto fbForDrawing = MozFramebuffer::CreateForBacking(
gl, size, 0, false, LOCAL_GL_RENDERBUFFER, data.interopRb->name);
if (!fbForDrawing) return nullptr;
// -
////
GLuint prodTex = 0;
GLuint interopFB = 0;
{
GLint samples = 0;
{
const ScopedBindRenderbuffer bindRB(gl, data.interopRb->name);
const ScopedBindRenderbuffer bindRB(gl, interopRB);
gl->fGetRenderbufferParameteriv(LOCAL_GL_RENDERBUFFER,
LOCAL_GL_RENDERBUFFER_SAMPLES, &samples);
}
@ -375,71 +372,104 @@ UniquePtr<SharedSurface_D3D11Interop> SharedSurface_D3D11Interop::Create(
// https://bugzilla.mozilla.org/show_bug.cgi?id=1325835
// Our ShSurf tex or rb must be single-sampled.
data.interopFbIfNeedsIndirect = std::move(fbForDrawing);
fbForDrawing = MozFramebuffer::Create(gl, size, 0, false);
gl->fGenTextures(1, &prodTex);
const ScopedBindTexture bindTex(gl, prodTex);
gl->TexParams_SetClampNoMips();
const GLenum format = (hasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB);
const ScopedBindPBO nullPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER);
gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, size.width, size.height,
0, format, LOCAL_GL_UNSIGNED_BYTE, nullptr);
gl->fGenFramebuffers(1, &interopFB);
ScopedBindFramebuffer bindFB(gl, interopFB);
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, interopRB);
MOZ_ASSERT(gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
LOCAL_GL_FRAMEBUFFER_COMPLETE);
}
}
// -
////
return AsUnique(new SharedSurface_D3D11Interop(desc, std::move(fbForDrawing),
std::move(data)));
typedef SharedSurface_D3D11Interop ptrT;
UniquePtr<ptrT> ret(new ptrT(gl, size, hasAlpha, prodTex, interopFB,
interopRB, interop, lockHandle, texD3D,
dxgiHandle));
return ret;
}
SharedSurface_D3D11Interop::SharedSurface_D3D11Interop(
const SharedSurfaceDesc& desc, UniquePtr<MozFramebuffer>&& fbForDrawing,
Data&& data)
: SharedSurface(desc, std::move(fbForDrawing)),
mData(std::move(data)),
mNeedsFinish(StaticPrefs::webgl_dxgl_needs_finish()) {}
GLContext* gl, const gfx::IntSize& size, bool hasAlpha, GLuint prodTex,
GLuint interopFB, GLuint interopRB, DXInterop2Device* interop,
HANDLE lockHandle, ID3D11Texture2D* texD3D, HANDLE dxgiHandle)
: SharedSurface(
SharedSurfaceType::DXGLInterop2,
prodTex ? AttachmentType::GLTexture : AttachmentType::GLRenderbuffer,
gl, size, hasAlpha, true),
mProdTex(prodTex),
mInteropFB(interopFB),
mInteropRB(interopRB),
mInterop(interop),
mLockHandle(lockHandle),
mTexD3D(texD3D),
mDXGIHandle(dxgiHandle),
mNeedsFinish(StaticPrefs::webgl_dxgl_needs_finish()),
mLockedForGL(false) {
MOZ_ASSERT(bool(mProdTex) == bool(mInteropFB));
}
SharedSurface_D3D11Interop::~SharedSurface_D3D11Interop() {
MOZ_ASSERT(!IsProducerAcquired());
const auto& gl = mDesc.gl;
if (!gl || !gl->MakeCurrent()) return;
if (!mGL || !mGL->MakeCurrent()) return;
if (!mData.interop->UnregisterObject(mData.lockHandle)) {
if (!mInterop->UnregisterObject(mLockHandle)) {
NS_WARNING("Failed to release mLockHandle, possibly leaking it.");
}
mGL->fDeleteTextures(1, &mProdTex);
mGL->fDeleteFramebuffers(1, &mInteropFB);
mGL->fDeleteRenderbuffers(1, &mInteropRB);
}
void SharedSurface_D3D11Interop::ProducerAcquireImpl() {
MOZ_ASSERT(!mLockedForGL);
// Now we have the mutex, we can lock for GL.
MOZ_ALWAYS_TRUE(mData.interop->LockObject(mData.lockHandle));
MOZ_ALWAYS_TRUE(mInterop->LockObject(mLockHandle));
mLockedForGL = true;
}
void SharedSurface_D3D11Interop::ProducerReleaseImpl() {
const auto& gl = mDesc.gl;
MOZ_ASSERT(mLockedForGL);
if (mData.interopFbIfNeedsIndirect) {
const ScopedBindFramebuffer bindFB(gl, mData.interopFbIfNeedsIndirect->mFB);
gl->BlitHelper()->DrawBlitTextureToFramebuffer(mFb->ColorTex(), mDesc.size,
mDesc.size);
if (mProdTex) {
const ScopedBindFramebuffer bindFB(mGL, mInteropFB);
mGL->BlitHelper()->DrawBlitTextureToFramebuffer(mProdTex, mSize, mSize);
}
if (mNeedsFinish) {
gl->fFinish();
mGL->fFinish();
} else {
// We probably don't even need this.
gl->fFlush();
mGL->fFlush();
}
MOZ_ALWAYS_TRUE(mData.interop->UnlockObject(mData.lockHandle));
MOZ_ALWAYS_TRUE(mInterop->UnlockObject(mLockHandle));
mLockedForGL = false;
}
Maybe<layers::SurfaceDescriptor>
SharedSurface_D3D11Interop::ToSurfaceDescriptor() {
const auto format = gfx::SurfaceFormat::B8G8R8A8;
return Some(layers::SurfaceDescriptorD3D10(
WindowsHandle(mData.dxgiHandle), format, mDesc.size,
gfx::YUVColorSpace::UNKNOWN, gfx::ColorRange::FULL));
bool SharedSurface_D3D11Interop::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
const auto format =
(mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::B8G8R8X8);
*out_descriptor = layers::SurfaceDescriptorD3D10(
WindowsHandle(mDXGIHandle), format, mSize, gfx::YUVColorSpace::UNKNOWN,
gfx::ColorRange::FULL);
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -447,30 +477,30 @@ SharedSurface_D3D11Interop::ToSurfaceDescriptor() {
/*static*/
UniquePtr<SurfaceFactory_D3D11Interop> SurfaceFactory_D3D11Interop::Create(
GLContext& gl) {
GLContext* gl, const SurfaceCaps& caps, layers::LayersIPCChannel* allocator,
const layers::TextureFlags& flags) {
WGLLibrary* wgl = &sWGLLib;
if (!wgl || !wgl->HasDXInterop2()) return nullptr;
if (XRE_IsContentProcess()) {
gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
}
const RefPtr<DXInterop2Device> interop = DXInterop2Device::Open(wgl, &gl);
const RefPtr<DXInterop2Device> interop = DXInterop2Device::Open(wgl, gl);
if (!interop) {
NS_WARNING("Failed to open D3D device for use by WGL.");
return nullptr;
}
return AsUnique(new SurfaceFactory_D3D11Interop(
{&gl, SharedSurfaceType::DXGLInterop2, layers::TextureType::D3D11, true},
interop));
typedef SurfaceFactory_D3D11Interop ptrT;
UniquePtr<ptrT> ret(new ptrT(gl, caps, allocator, flags, interop));
return ret;
}
SurfaceFactory_D3D11Interop::SurfaceFactory_D3D11Interop(
const PartialSharedSurfaceDesc& desc, DXInterop2Device* interop)
: SurfaceFactory(desc), mInterop(interop) {}
GLContext* gl, const SurfaceCaps& caps, layers::LayersIPCChannel* allocator,
const layers::TextureFlags& flags, DXInterop2Device* interop)
: SurfaceFactory(SharedSurfaceType::DXGLInterop2, gl, caps, allocator,
flags),
mInterop(interop) {}
SurfaceFactory_D3D11Interop::~SurfaceFactory_D3D11Interop() = default;
SurfaceFactory_D3D11Interop::~SurfaceFactory_D3D11Interop() {}
} // namespace gl
} // namespace mozilla

Просмотреть файл

@ -16,29 +16,37 @@ class DXInterop2Device;
class GLContext;
class WGLLibrary;
class SharedSurface_D3D11Interop final : public SharedSurface {
class SharedSurface_D3D11Interop : public SharedSurface {
public:
struct Data final {
const RefPtr<DXInterop2Device> interop;
HANDLE lockHandle;
RefPtr<ID3D11Texture2D> texD3D;
HANDLE dxgiHandle;
UniquePtr<Renderbuffer> interopRb;
UniquePtr<MozFramebuffer> interopFbIfNeedsIndirect;
};
const Data mData;
const GLuint mProdTex;
const GLuint mInteropFB;
const GLuint mInteropRB;
const RefPtr<DXInterop2Device> mInterop;
const HANDLE mLockHandle;
const RefPtr<ID3D11Texture2D> mTexD3D;
const HANDLE mDXGIHandle;
const bool mNeedsFinish;
private:
bool mLockedForGL = false;
protected:
bool mLockedForGL;
public:
static UniquePtr<SharedSurface_D3D11Interop> Create(const SharedSurfaceDesc&,
DXInterop2Device*);
static UniquePtr<SharedSurface_D3D11Interop> Create(DXInterop2Device* interop,
GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha);
private:
SharedSurface_D3D11Interop(const SharedSurfaceDesc&,
UniquePtr<MozFramebuffer>&& fbForDrawing, Data&&);
static SharedSurface_D3D11Interop* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::DXGLInterop2);
return (SharedSurface_D3D11Interop*)surf;
}
protected:
SharedSurface_D3D11Interop(GLContext* gl, const gfx::IntSize& size,
bool hasAlpha, GLuint prodTex, GLuint interopFB,
GLuint interopRB, DXInterop2Device* interop,
HANDLE lockHandle, ID3D11Texture2D* texD3D,
HANDLE dxgiHandle);
public:
virtual ~SharedSurface_D3D11Interop();
@ -49,26 +57,41 @@ class SharedSurface_D3D11Interop final : public SharedSurface {
void ProducerAcquireImpl() override;
void ProducerReleaseImpl() override;
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
GLuint ProdRenderbuffer() override {
MOZ_ASSERT(!mProdTex);
return mInteropRB;
}
GLuint ProdTexture() override {
MOZ_ASSERT(mProdTex);
return mProdTex;
}
bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
};
class SurfaceFactory_D3D11Interop : public SurfaceFactory {
public:
const RefPtr<DXInterop2Device> mInterop;
static UniquePtr<SurfaceFactory_D3D11Interop> Create(GLContext& gl);
static UniquePtr<SurfaceFactory_D3D11Interop> Create(
GLContext* gl, const SurfaceCaps& caps,
layers::LayersIPCChannel* allocator, const layers::TextureFlags& flags);
protected:
SurfaceFactory_D3D11Interop(const PartialSharedSurfaceDesc&,
SurfaceFactory_D3D11Interop(GLContext* gl, const SurfaceCaps& caps,
layers::LayersIPCChannel* allocator,
const layers::TextureFlags& flags,
DXInterop2Device* interop);
public:
virtual ~SurfaceFactory_D3D11Interop();
protected:
UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override {
return SharedSurface_D3D11Interop::Create(desc, mInterop);
UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_D3D11Interop::Create(mInterop, mGL, size, hasAlpha);
}
};

Просмотреть файл

@ -4,41 +4,42 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedSurfaceDMABUF.h"
#include "GLContextEGL.h"
#include "MozFramebuffer.h"
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
namespace mozilla::gl {
/*static*/
UniquePtr<SharedSurface_DMABUF> SharedSurface_DMABUF::Create(
const SharedSurfaceDesc& desc) {
const auto flags = static_cast<WaylandDMABufSurfaceFlags>(
DMABUF_TEXTURE | DMABUF_USE_MODIFIERS | DMABUF_ALPHA);
const RefPtr<WaylandDMABufSurface> surface =
WaylandDMABufSurfaceRGBA::CreateDMABufSurface(desc.size.width,
desc.size.height, flags);
if (!surface || !surface->CreateTexture(desc.gl)) {
GLContext* prodGL, const GLFormats& formats, const gfx::IntSize& size,
bool hasAlpha) {
auto flags = static_cast<WaylandDMABufSurfaceFlags>(DMABUF_TEXTURE |
DMABUF_USE_MODIFIERS);
if (hasAlpha) {
flags = static_cast<WaylandDMABufSurfaceFlags>(flags | DMABUF_ALPHA);
}
RefPtr<WaylandDMABufSurface> surface =
WaylandDMABufSurfaceRGBA::CreateDMABufSurface(size.width, size.height,
flags);
if (!surface || !surface->CreateTexture(prodGL)) {
return nullptr;
}
const auto tex = surface->GetTexture();
auto fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false,
LOCAL_GL_TEXTURE_2D, tex);
if (!fb) return nullptr;
return AsUnique(new SharedSurface_DMABUF(desc, std::move(fb), surface));
UniquePtr<SharedSurface_DMABUF> ret;
ret.reset(new SharedSurface_DMABUF(prodGL, size, hasAlpha, surface));
return ret;
}
SharedSurface_DMABUF::SharedSurface_DMABUF(
const SharedSurfaceDesc& desc, UniquePtr<MozFramebuffer> fb,
const RefPtr<WaylandDMABufSurface> surface)
: SharedSurface(desc, std::move(fb)), mSurface(surface) {}
GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
RefPtr<WaylandDMABufSurface> aSurface)
: SharedSurface(SharedSurfaceType::EGLSurfaceDMABUF,
AttachmentType::GLTexture, gl, size, hasAlpha, true),
mSurface(aSurface) {}
SharedSurface_DMABUF::~SharedSurface_DMABUF() {
const auto& gl = mDesc.gl;
if (!gl || !gl->MakeCurrent()) {
if (!mGL || !mGL->MakeCurrent()) {
return;
}
mSurface->ReleaseTextures();
@ -46,14 +47,10 @@ SharedSurface_DMABUF::~SharedSurface_DMABUF() {
void SharedSurface_DMABUF::ProducerReleaseImpl() { mSurface->FenceSet(); }
Maybe<layers::SurfaceDescriptor> SharedSurface_DMABUF::ToSurfaceDescriptor() {
layers::SurfaceDescriptor desc;
if (!mSurface->Serialize(desc)) return {};
return Some(desc);
bool SharedSurface_DMABUF::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
MOZ_ASSERT(mSurface);
return mSurface->Serialize(*out_descriptor);
}
SurfaceFactory_DMABUF::SurfaceFactory_DMABUF(GLContext& gl)
: SurfaceFactory({&gl, SharedSurfaceType::EGLSurfaceDMABUF,
layers::TextureType::WaylandDMABUF, true}) {}
} // namespace mozilla::gl

Просмотреть файл

@ -17,13 +17,22 @@ class GLLibraryEGL;
class SharedSurface_DMABUF final : public SharedSurface {
public:
const RefPtr<WaylandDMABufSurface> mSurface;
static UniquePtr<SharedSurface_DMABUF> Create(GLContext* prodGL,
const GLFormats& formats,
const gfx::IntSize& size,
bool hasAlpha);
static UniquePtr<SharedSurface_DMABUF> Create(const SharedSurfaceDesc&);
static SharedSurface_DMABUF* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::EGLSurfaceDMABUF);
private:
SharedSurface_DMABUF(const SharedSurfaceDesc&, UniquePtr<MozFramebuffer>,
RefPtr<WaylandDMABufSurface>);
return (SharedSurface_DMABUF*)surf;
}
protected:
RefPtr<WaylandDMABufSurface> mSurface;
SharedSurface_DMABUF(GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
RefPtr<WaylandDMABufSurface> aSurface);
void UpdateProdTexture(const MutexAutoLock& curAutoLock);
@ -42,17 +51,25 @@ class SharedSurface_DMABUF final : public SharedSurface {
virtual void ProducerReadAcquireImpl() override {}
virtual void ProducerReadReleaseImpl() override {}
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
virtual GLuint ProdTexture() override { return mSurface->GetTexture(); }
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
};
class SurfaceFactory_DMABUF : public SurfaceFactory {
public:
explicit SurfaceFactory_DMABUF(GLContext&);
SurfaceFactory_DMABUF(GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags)
: SurfaceFactory(SharedSurfaceType::EGLSurfaceDMABUF, prodGL, caps,
allocator, flags){};
public:
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override {
return SharedSurface_DMABUF::Create(desc);
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_DMABUF::Create(mGL, mFormats, size, hasAlpha);
}
};

Просмотреть файл

@ -5,13 +5,11 @@
#include "SharedSurfaceEGL.h"
#include "AndroidNativeWindow.h"
#include "GLBlitHelper.h"
#include "GLContextEGL.h"
#include "GLContextProvider.h"
#include "GLLibraryEGL.h"
#include "GLReadTexImageHelper.h"
#include "MozFramebuffer.h"
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
#include "SharedSurface.h"
@ -22,56 +20,66 @@
namespace mozilla {
namespace gl {
static bool HasEglImageExtensions(const GLContextEGL& gl) {
const auto& egl = *(gl.mEgl);
return egl.HasKHRImageBase() &&
egl.IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) &&
(gl.IsExtensionSupported(GLContext::OES_EGL_image_external) ||
gl.IsExtensionSupported(GLContext::OES_EGL_image));
}
/*static*/
UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create(
GLContext& gl_) {
auto& gl = *GLContextEGL::Cast(&gl_);
if (!HasEglImageExtensions(gl)) return nullptr;
const auto partialDesc = PartialSharedSurfaceDesc{
&gl, SharedSurfaceType::EGLImageShare, layers::TextureType::EGLImage,
false, // Can't recycle, as mSync changes never update TextureHost.
};
return AsUnique(new SurfaceFactory_EGLImage(partialDesc));
}
// -
/*static*/
UniquePtr<SharedSurface_EGLImage> SharedSurface_EGLImage::Create(
const SharedSurfaceDesc& desc) {
const auto& gle = GLContextEGL::Cast(desc.gl);
const auto& context = gle->mContext;
const auto& egl = *(gle->mEgl);
GLContext* prodGL, const GLFormats& formats, const gfx::IntSize& size,
bool hasAlpha, EGLContext context) {
const auto& gle = GLContextEGL::Cast(prodGL);
const auto& egl = gle->mEgl;
MOZ_ASSERT(egl);
MOZ_ASSERT(context);
auto fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false);
if (!fb) return nullptr;
UniquePtr<SharedSurface_EGLImage> ret;
const auto buffer = reinterpret_cast<EGLClientBuffer>(fb->ColorTex());
const auto image = egl.fCreateImage(egl.Display(), context,
LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr);
if (!image) return nullptr;
if (!HasExtensions(egl, prodGL)) {
return ret;
}
return AsUnique(new SharedSurface_EGLImage(desc, std::move(fb), image));
MOZ_ALWAYS_TRUE(prodGL->MakeCurrent());
GLuint prodTex = CreateTextureForOffscreen(prodGL, formats, size);
if (!prodTex) {
return ret;
}
EGLClientBuffer buffer =
reinterpret_cast<EGLClientBuffer>(uintptr_t(prodTex));
EGLImage image = egl->fCreateImage(egl->Display(), context,
LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr);
if (!image) {
prodGL->fDeleteTextures(1, &prodTex);
return ret;
}
ret.reset(new SharedSurface_EGLImage(prodGL, size, hasAlpha, formats, prodTex,
image));
return ret;
}
SharedSurface_EGLImage::SharedSurface_EGLImage(const SharedSurfaceDesc& desc,
UniquePtr<MozFramebuffer>&& fb,
const EGLImage image)
: SharedSurface(desc, std::move(fb)),
bool SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) {
return egl->HasKHRImageBase() &&
egl->IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) &&
(gl->IsExtensionSupported(GLContext::OES_EGL_image_external) ||
gl->IsExtensionSupported(GLContext::OES_EGL_image));
}
SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha,
const GLFormats& formats,
GLuint prodTex, EGLImage image)
: SharedSurface(
SharedSurfaceType::EGLImageShare, AttachmentType::GLTexture, gl, size,
hasAlpha,
false) // Can't recycle, as mSync changes never update TextureHost.
,
mMutex("SharedSurface_EGLImage mutex"),
mImage(image) {}
mFormats(formats),
mProdTex(prodTex),
mImage(image),
mSync(0) {}
SharedSurface_EGLImage::~SharedSurface_EGLImage() {
const auto& gle = GLContextEGL::Cast(mDesc.gl);
const auto& gle = GLContextEGL::Cast(mGL);
const auto& egl = gle->mEgl;
egl->fDestroyImage(egl->Display(), mImage);
@ -81,17 +89,22 @@ SharedSurface_EGLImage::~SharedSurface_EGLImage() {
egl->fDestroySync(egl->Display(), mSync);
mSync = 0;
}
if (!mGL || !mGL->MakeCurrent()) return;
mGL->fDeleteTextures(1, &mProdTex);
mProdTex = 0;
}
void SharedSurface_EGLImage::ProducerReleaseImpl() {
const auto& gl = GLContextEGL::Cast(mDesc.gl);
const auto& egl = gl->mEgl;
const auto& gle = GLContextEGL::Cast(mGL);
const auto& egl = gle->mEgl;
MutexAutoLock lock(mMutex);
gl->MakeCurrent();
mGL->MakeCurrent();
if (egl->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
gl->IsExtensionSupported(GLContext::OES_EGL_sync)) {
mGL->IsExtensionSupported(GLContext::OES_EGL_sync)) {
if (mSync) {
MOZ_RELEASE_ASSERT(false, "GFX: Non-recycleable should not Fence twice.");
MOZ_ALWAYS_TRUE(egl->fDestroySync(egl->Display(), mSync));
@ -100,17 +113,17 @@ void SharedSurface_EGLImage::ProducerReleaseImpl() {
mSync = egl->fCreateSync(egl->Display(), LOCAL_EGL_SYNC_FENCE, nullptr);
if (mSync) {
gl->fFlush();
mGL->fFlush();
return;
}
}
MOZ_ASSERT(!mSync);
gl->fFinish();
mGL->fFinish();
}
void SharedSurface_EGLImage::ProducerReadAcquireImpl() {
const auto& gle = GLContextEGL::Cast(mDesc.gl);
const auto& gle = GLContextEGL::Cast(mGL);
const auto& egl = gle->mEgl;
// Wait on the fence, because presumably we're going to want to read this
// surface
@ -119,14 +132,16 @@ void SharedSurface_EGLImage::ProducerReadAcquireImpl() {
}
}
Maybe<layers::SurfaceDescriptor> SharedSurface_EGLImage::ToSurfaceDescriptor() {
return Some(layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync,
mDesc.size, true));
bool SharedSurface_EGLImage::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
*out_descriptor = layers::EGLImageDescriptor(
(uintptr_t)mImage, (uintptr_t)mSync, mSize, mHasAlpha);
return true;
}
bool SharedSurface_EGLImage::ReadbackBySharedHandle(
gfx::DataSourceSurface* out_surface) {
const auto& gle = GLContextEGL::Cast(mDesc.gl);
const auto& gle = GLContextEGL::Cast(mGL);
const auto& egl = gle->mEgl;
MOZ_ASSERT(out_surface);
MOZ_ASSERT(NS_IsMainThread());
@ -135,40 +150,56 @@ bool SharedSurface_EGLImage::ReadbackBySharedHandle(
////////////////////////////////////////////////////////////////////////
/*static*/
UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create(
GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags) {
const auto& gle = GLContextEGL::Cast(prodGL);
const auto& egl = gle->mEgl;
const auto& context = gle->mContext;
typedef SurfaceFactory_EGLImage ptrT;
UniquePtr<ptrT> ret;
if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
ret.reset(new ptrT(prodGL, caps, allocator, flags, context));
}
return ret;
}
////////////////////////////////////////////////////////////////////////
#ifdef MOZ_WIDGET_ANDROID
/*static*/
UniquePtr<SharedSurface_SurfaceTexture> SharedSurface_SurfaceTexture::Create(
const SharedSurfaceDesc& desc) {
const auto& size = desc.size;
GLContext* prodGL, const GLFormats& formats, const gfx::IntSize& size,
bool hasAlpha, java::GeckoSurface::Param surface) {
MOZ_ASSERT(surface);
jni::Object::LocalRef surfaceObj =
java::SurfaceAllocator::AcquireSurface(size.width, size.height, true);
if (!surfaceObj) {
// Try multi-buffer mode
surfaceObj =
java::SurfaceAllocator::AcquireSurface(size.width, size.height, false);
}
if (!surfaceObj) {
// Give up
NS_WARNING("Failed to allocate SurfaceTexture!");
return nullptr;
}
const auto surface = java::GeckoSurface::Ref::From(surfaceObj);
UniquePtr<SharedSurface_SurfaceTexture> ret;
AndroidNativeWindow window(surface);
const auto& gle = GLContextEGL::Cast(desc.gl);
const auto& gle = GLContextEGL::Cast(prodGL);
MOZ_ASSERT(gle);
const auto eglSurface = gle->CreateCompatibleSurface(window.NativeWindow());
if (!eglSurface) return nullptr;
EGLSurface eglSurface = gle->CreateCompatibleSurface(window.NativeWindow());
if (!eglSurface) {
return ret;
}
return AsUnique(new SharedSurface_SurfaceTexture(desc, surface, eglSurface));
ret.reset(new SharedSurface_SurfaceTexture(prodGL, size, hasAlpha, formats,
surface, eglSurface));
return ret;
}
SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture(
const SharedSurfaceDesc& desc, java::GeckoSurface::Param surface,
const EGLSurface eglSurface)
: SharedSurface(desc, nullptr),
GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
const GLFormats& formats, java::GeckoSurface::Param surface,
EGLSurface eglSurface)
: SharedSurface(SharedSurfaceType::AndroidSurfaceTexture,
AttachmentType::Screen, gl, size, hasAlpha, true),
mSurface(surface),
mEglSurface(eglSurface) {}
@ -186,7 +217,7 @@ SharedSurface_SurfaceTexture::~SharedSurface_SurfaceTexture() {
void SharedSurface_SurfaceTexture::LockProdImpl() {
MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl);
GLContextEGL* gl = GLContextEGL::Cast(mGL);
mOrigEglSurface = gl->GetEGLSurfaceOverride();
gl->SetEGLSurfaceOverride(mEglSurface);
}
@ -194,7 +225,7 @@ void SharedSurface_SurfaceTexture::LockProdImpl() {
void SharedSurface_SurfaceTexture::UnlockProdImpl() {
MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl);
GLContextEGL* gl = GLContextEGL::Cast(mGL);
MOZ_ASSERT(gl->GetEGLSurfaceOverride() == mEglSurface);
gl->SetEGLSurfaceOverride(mOrigEglSurface);
@ -205,7 +236,7 @@ void SharedSurface_SurfaceTexture::Commit() {
MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
LockProdImpl();
mDesc.gl->SwapBuffers();
mGL->SwapBuffers();
UnlockProdImpl();
mSurface->SetAvailable(false);
}
@ -218,16 +249,46 @@ bool SharedSurface_SurfaceTexture::IsBufferAvailable() const {
return mSurface->GetAvailable();
}
Maybe<layers::SurfaceDescriptor>
SharedSurface_SurfaceTexture::ToSurfaceDescriptor() {
return Some(layers::SurfaceTextureDescriptor(
mSurface->GetHandle(), mDesc.size, gfx::SurfaceFormat::R8G8B8A8,
false /* NOT continuous */, false /* Do not ignore transform */));
bool SharedSurface_SurfaceTexture::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
*out_descriptor = layers::SurfaceTextureDescriptor(
mSurface->GetHandle(), mSize, gfx::SurfaceFormat::R8G8B8A8,
false /* NOT continuous */, false /* Do not ignore transform */);
return true;
}
SurfaceFactory_SurfaceTexture::SurfaceFactory_SurfaceTexture(GLContext& gl)
: SurfaceFactory({&gl, SharedSurfaceType::AndroidSurfaceTexture,
layers::TextureType::AndroidNativeWindow, true}) {}
////////////////////////////////////////////////////////////////////////
/*static*/
UniquePtr<SurfaceFactory_SurfaceTexture> SurfaceFactory_SurfaceTexture::Create(
GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags) {
UniquePtr<SurfaceFactory_SurfaceTexture> ret(
new SurfaceFactory_SurfaceTexture(prodGL, caps, allocator, flags));
return ret;
}
UniquePtr<SharedSurface> SurfaceFactory_SurfaceTexture::CreateShared(
const gfx::IntSize& size) {
bool hasAlpha = mReadCaps.alpha;
jni::Object::LocalRef surface =
java::SurfaceAllocator::AcquireSurface(size.width, size.height, true);
if (!surface) {
// Try multi-buffer mode
surface =
java::SurfaceAllocator::AcquireSurface(size.width, size.height, false);
if (!surface) {
// Give up
NS_WARNING("Failed to allocate SurfaceTexture!");
return nullptr;
}
}
return SharedSurface_SurfaceTexture::Create(
mGL, mFormats, size, hasAlpha, java::GeckoSurface::Ref::From(surface));
}
#endif // MOZ_WIDGET_ANDROID

Просмотреть файл

@ -18,29 +18,49 @@
namespace mozilla {
namespace gl {
class GLContext;
class GLLibraryEGL;
// -
// EGLImage
class SharedSurface_EGLImage : public SharedSurface {
public:
static UniquePtr<SharedSurface_EGLImage> Create(GLContext* prodGL,
const GLFormats& formats,
const gfx::IntSize& size,
bool hasAlpha,
EGLContext context);
class SharedSurface_EGLImage final : public SharedSurface {
static SharedSurface_EGLImage* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::EGLImageShare);
return (SharedSurface_EGLImage*)surf;
}
static bool HasExtensions(GLLibraryEGL* egl, GLContext* gl);
protected:
mutable Mutex mMutex;
EGLSync mSync = 0;
const GLFormats mFormats;
GLuint mProdTex;
public:
const EGLImage mImage;
static UniquePtr<SharedSurface_EGLImage> Create(const SharedSurfaceDesc&);
protected:
SharedSurface_EGLImage(const SharedSurfaceDesc&,
UniquePtr<MozFramebuffer>&& fb, EGLImage);
EGLSync mSync;
SharedSurface_EGLImage(GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
const GLFormats& formats, GLuint prodTex,
EGLImage image);
void UpdateProdTexture(const MutexAutoLock& curAutoLock);
public:
virtual ~SharedSurface_EGLImage();
virtual layers::TextureFlags GetTextureFlags() const override {
return layers::TextureFlags::DEALLOCATE_CLIENT;
}
virtual void LockProdImpl() override {}
virtual void UnlockProdImpl() override {}
@ -50,46 +70,69 @@ class SharedSurface_EGLImage final : public SharedSurface {
virtual void ProducerReadAcquireImpl() override;
virtual void ProducerReadReleaseImpl() override{};
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
virtual GLuint ProdTexture() override { return mProdTex; }
// Implementation-specific functions below:
// Returns texture and target
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
virtual bool ReadbackBySharedHandle(
gfx::DataSourceSurface* out_surface) override;
};
class SurfaceFactory_EGLImage final : public SurfaceFactory {
class SurfaceFactory_EGLImage : public SurfaceFactory {
public:
static UniquePtr<SurfaceFactory_EGLImage> Create(GLContext&);
// Fallible:
static UniquePtr<SurfaceFactory_EGLImage> Create(
GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags);
private:
explicit SurfaceFactory_EGLImage(const PartialSharedSurfaceDesc& desc)
: SurfaceFactory(desc) {}
protected:
const EGLContext mContext;
SurfaceFactory_EGLImage(GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags, EGLContext context)
: SurfaceFactory(SharedSurfaceType::EGLImageShare, prodGL, caps,
allocator, flags),
mContext(context) {}
public:
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override {
return SharedSurface_EGLImage::Create(desc);
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_EGLImage::Create(mGL, mFormats, size, hasAlpha,
mContext);
}
};
// -
// SurfaceTexture
#ifdef MOZ_WIDGET_ANDROID
class SharedSurface_SurfaceTexture final : public SharedSurface {
const java::GeckoSurface::GlobalRef mSurface;
const EGLSurface mEglSurface;
EGLSurface mOrigEglSurface = 0;
class SharedSurface_SurfaceTexture : public SharedSurface {
public:
static UniquePtr<SharedSurface_SurfaceTexture> Create(
const SharedSurfaceDesc&);
GLContext* prodGL, const GLFormats& formats, const gfx::IntSize& size,
bool hasAlpha, java::GeckoSurface::Param surface);
static SharedSurface_SurfaceTexture* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::AndroidSurfaceTexture);
return (SharedSurface_SurfaceTexture*)surf;
}
java::GeckoSurface::Param JavaSurface() { return mSurface; }
protected:
SharedSurface_SurfaceTexture(const SharedSurfaceDesc&,
java::GeckoSurface::Param surface, EGLSurface);
java::GeckoSurface::GlobalRef mSurface;
EGLSurface mEglSurface;
EGLSurface mOrigEglSurface;
SharedSurface_SurfaceTexture(GLContext* gl, const gfx::IntSize& size,
bool hasAlpha, const GLFormats& formats,
java::GeckoSurface::Param surface,
EGLSurface eglSurface);
public:
virtual ~SharedSurface_SurfaceTexture();
@ -100,7 +143,18 @@ class SharedSurface_SurfaceTexture final : public SharedSurface {
virtual void ProducerAcquireImpl() override {}
virtual void ProducerReleaseImpl() override {}
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
virtual void ProducerReadAcquireImpl() override {}
virtual void ProducerReadReleaseImpl() override {}
// Implementation-specific functions below:
// Returns texture and target
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
virtual bool ReadbackBySharedHandle(
gfx::DataSourceSurface* out_surface) override {
return false;
}
virtual void Commit() override;
@ -109,14 +163,25 @@ class SharedSurface_SurfaceTexture final : public SharedSurface {
virtual bool IsBufferAvailable() const override;
};
class SurfaceFactory_SurfaceTexture final : public SurfaceFactory {
class SurfaceFactory_SurfaceTexture : public SurfaceFactory {
public:
explicit SurfaceFactory_SurfaceTexture(GLContext&);
// Fallible:
static UniquePtr<SurfaceFactory_SurfaceTexture> Create(
GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags);
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override {
return SharedSurface_SurfaceTexture::Create(desc);
}
protected:
SurfaceFactory_SurfaceTexture(
GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags)
: SurfaceFactory(SharedSurfaceType::AndroidSurfaceTexture, prodGL, caps,
allocator, flags) {}
public:
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override;
};
#endif // MOZ_WIDGET_ANDROID

Просмотреть файл

@ -15,28 +15,145 @@
namespace mozilla {
namespace gl {
using gfx::IntSize;
using gfx::SurfaceFormat;
/*static*/
UniquePtr<SharedSurface_Basic> SharedSurface_Basic::Create(
const SharedSurfaceDesc& desc) {
auto fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false);
if (!fb) return nullptr;
GLContext* gl, const GLFormats& formats, const IntSize& size,
bool hasAlpha) {
UniquePtr<SharedSurface_Basic> ret;
gl->MakeCurrent();
return AsUnique(new SharedSurface_Basic(desc, std::move(fb)));
GLContext::LocalErrorScope localError(*gl);
GLuint tex = CreateTextureForOffscreen(gl, formats, size);
GLenum err = localError.GetError();
MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
if (err) {
gl->fDeleteTextures(1, &tex);
return ret;
}
bool ownsTex = true;
ret.reset(new SharedSurface_Basic(gl, size, hasAlpha, tex, ownsTex));
return ret;
}
SharedSurface_Basic::SharedSurface_Basic(const SharedSurfaceDesc& desc,
UniquePtr<MozFramebuffer>&& fb)
: SharedSurface(desc, std::move(fb)) {}
/*static*/
UniquePtr<SharedSurface_Basic> SharedSurface_Basic::Wrap(GLContext* gl,
const IntSize& size,
bool hasAlpha,
GLuint tex) {
bool ownsTex = false;
UniquePtr<SharedSurface_Basic> ret(
new SharedSurface_Basic(gl, size, hasAlpha, tex, ownsTex));
return ret;
}
Maybe<layers::SurfaceDescriptor> SharedSurface_Basic::ToSurfaceDescriptor() {
return Nothing();
SharedSurface_Basic::SharedSurface_Basic(GLContext* gl, const IntSize& size,
bool hasAlpha, GLuint tex,
bool ownsTex)
: SharedSurface(SharedSurfaceType::Basic, AttachmentType::GLTexture, gl,
size, hasAlpha, true),
mTex(tex),
mOwnsTex(ownsTex),
mFB(0) {
mGL->MakeCurrent();
mGL->fGenFramebuffers(1, &mFB);
ScopedBindFramebuffer autoFB(mGL, mFB);
mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_TEXTURE_2D, mTex, 0);
DebugOnly<GLenum> status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
}
SharedSurface_Basic::~SharedSurface_Basic() {
if (!mGL || !mGL->MakeCurrent()) return;
if (mFB) mGL->fDeleteFramebuffers(1, &mFB);
if (mOwnsTex) mGL->fDeleteTextures(1, &mTex);
}
////////////////////////////////////////////////////////////////////////
SurfaceFactory_Basic::SurfaceFactory_Basic(GLContext& gl)
: SurfaceFactory({&gl, SharedSurfaceType::Basic,
layers::TextureType::Unknown, true}) {}
SurfaceFactory_Basic::SurfaceFactory_Basic(GLContext* gl,
const SurfaceCaps& caps,
const layers::TextureFlags& flags)
: SurfaceFactory(SharedSurfaceType::Basic, gl, caps, nullptr, flags) {}
////////////////////////////////////////////////////////////////////////
// SharedSurface_GLTexture
/*static*/
UniquePtr<SharedSurface_GLTexture> SharedSurface_GLTexture::Create(
GLContext* prodGL, const GLFormats& formats, const IntSize& size,
bool hasAlpha) {
MOZ_ASSERT(prodGL);
prodGL->MakeCurrent();
UniquePtr<SharedSurface_GLTexture> ret;
GLContext::LocalErrorScope localError(*prodGL);
GLuint tex = CreateTextureForOffscreen(prodGL, formats, size);
GLenum err = localError.GetError();
MOZ_ASSERT_IF(err, err == LOCAL_GL_OUT_OF_MEMORY);
if (err) {
prodGL->fDeleteTextures(1, &tex);
return ret;
}
ret.reset(new SharedSurface_GLTexture(prodGL, size, hasAlpha, tex));
return ret;
}
SharedSurface_GLTexture::~SharedSurface_GLTexture() {
if (!mGL->MakeCurrent()) return;
if (mTex) {
mGL->fDeleteTextures(1, &mTex);
}
if (mSync) {
mGL->fDeleteSync(mSync);
}
}
void SharedSurface_GLTexture::ProducerReleaseImpl() {
mGL->MakeCurrent();
if (mGL->IsSupported(GLFeature::sync)) {
if (mSync) {
mGL->fDeleteSync(mSync);
mSync = 0;
}
mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
if (mSync) {
mGL->fFlush();
return;
}
}
MOZ_ASSERT(!mSync);
mGL->fFinish();
}
bool SharedSurface_GLTexture::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
*out_descriptor = layers::SurfaceDescriptorSharedGLTexture(
ProdTexture(), ProdTextureTarget(), (uintptr_t)mSync, mSize, mHasAlpha);
// Transfer ownership of the fence to the host
mSync = nullptr;
return true;
}
} // namespace gl
} // namespace mozilla
} /* namespace mozilla */

Просмотреть файл

@ -6,37 +6,140 @@
#ifndef SHARED_SURFACE_GL_H_
#define SHARED_SURFACE_GL_H_
#include "ScopedGLHelpers.h"
#include "SharedSurface.h"
#include "SurfaceTypes.h"
#include "GLContextTypes.h"
#include "gfxTypes.h"
#include "mozilla/Mutex.h"
#include <queue>
namespace mozilla {
namespace gl {
class GLContext;
} // namespace gl
namespace gfx {
class DataSourceSurface;
} // namespace gfx
} // namespace mozilla
namespace mozilla {
namespace gl {
class MozFramebuffer;
// For readback and bootstrapping:
class SharedSurface_Basic final : public SharedSurface {
class SharedSurface_Basic : public SharedSurface {
public:
static UniquePtr<SharedSurface_Basic> Create(const SharedSurfaceDesc&);
static UniquePtr<SharedSurface_Basic> Create(GLContext* gl,
const GLFormats& formats,
const gfx::IntSize& size,
bool hasAlpha);
private:
SharedSurface_Basic(const SharedSurfaceDesc& desc,
UniquePtr<MozFramebuffer>&& fb);
static UniquePtr<SharedSurface_Basic> Wrap(GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha, GLuint tex);
static SharedSurface_Basic* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::Basic);
return (SharedSurface_Basic*)surf;
}
protected:
const GLuint mTex;
const bool mOwnsTex;
GLuint mFB;
SharedSurface_Basic(GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
GLuint tex, bool ownsTex);
public:
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
virtual ~SharedSurface_Basic();
virtual void LockProdImpl() override {}
virtual void UnlockProdImpl() override {}
virtual void ProducerAcquireImpl() override {}
virtual void ProducerReleaseImpl() override {}
virtual GLuint ProdTexture() override { return mTex; }
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override {
MOZ_CRASH("GFX: ToSurfaceDescriptor");
return false;
}
};
class SurfaceFactory_Basic final : public SurfaceFactory {
class SurfaceFactory_Basic : public SurfaceFactory {
public:
explicit SurfaceFactory_Basic(GLContext& gl);
SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps,
const layers::TextureFlags& flags);
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override {
return SharedSurface_Basic::Create(desc);
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_Basic::Create(mGL, mFormats, size, hasAlpha);
}
};
// Using shared GL textures:
class SharedSurface_GLTexture : public SharedSurface {
public:
static UniquePtr<SharedSurface_GLTexture> Create(GLContext* prodGL,
const GLFormats& formats,
const gfx::IntSize& size,
bool hasAlpha);
static SharedSurface_GLTexture* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::SharedGLTexture);
return (SharedSurface_GLTexture*)surf;
}
protected:
const GLuint mTex;
GLsync mSync;
SharedSurface_GLTexture(GLContext* prodGL, const gfx::IntSize& size,
bool hasAlpha, GLuint tex)
: SharedSurface(SharedSurfaceType::SharedGLTexture,
AttachmentType::GLTexture, prodGL, size, hasAlpha, true),
mTex(tex),
mSync(0) {}
public:
virtual ~SharedSurface_GLTexture();
virtual void LockProdImpl() override {}
virtual void UnlockProdImpl() override {}
virtual void ProducerAcquireImpl() override {}
virtual void ProducerReleaseImpl() override;
virtual GLuint ProdTexture() override { return mTex; }
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
};
class SurfaceFactory_GLTexture : public SurfaceFactory {
public:
SurfaceFactory_GLTexture(GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags)
: SurfaceFactory(SharedSurfaceType::SharedGLTexture, prodGL, caps,
allocator, flags) {}
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_GLTexture::Create(mGL, mFormats, size, hasAlpha);
}
};
} // namespace gl
} // namespace mozilla
#endif // SHARED_SURFACE_GL_H_
} /* namespace mozilla */
#endif /* SHARED_SURFACE_GL_H_ */

Просмотреть файл

@ -9,7 +9,6 @@
#include "GLContextProvider.h"
#include "GLContextGLX.h"
#include "GLScreenBuffer.h"
#include "MozFramebuffer.h"
#include "mozilla/gfx/SourceSurfaceCairo.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/ShadowLayerUtilsX11.h"
@ -19,50 +18,50 @@
namespace mozilla::gl {
UniquePtr<SharedSurface> SurfaceFactory_GLXDrawable::CreateSharedImpl(
const SharedSurfaceDesc& desc) {
return SharedSurface_GLXDrawable::Create(desc);
}
/* static */
UniquePtr<SharedSurface_GLXDrawable> SharedSurface_GLXDrawable::Create(
const SharedSurfaceDesc& desc) {
GLContext* prodGL, const SurfaceCaps& caps, const gfx::IntSize& size,
bool deallocateClient, bool inSameProcess) {
UniquePtr<SharedSurface_GLXDrawable> ret;
Display* display = DefaultXDisplay();
Screen* screen = XDefaultScreenOfDisplay(display);
Visual* visual =
gfxXlibSurface::FindVisual(screen, gfx::SurfaceFormat::A8R8G8B8_UINT32);
const RefPtr<gfxXlibSurface> surf =
gfxXlibSurface::Create(screen, visual, desc.size);
surf->ReleasePixmap();
RefPtr<gfxXlibSurface> surf = gfxXlibSurface::Create(screen, visual, size);
if (!deallocateClient) surf->ReleasePixmap();
return AsUnique(new SharedSurface_GLXDrawable(desc, surf));
ret.reset(new SharedSurface_GLXDrawable(prodGL, size, inSameProcess, surf));
return ret;
}
SharedSurface_GLXDrawable::SharedSurface_GLXDrawable(
const SharedSurfaceDesc& desc, const RefPtr<gfxXlibSurface>& xlibSurface)
: SharedSurface(desc, nullptr), mXlibSurface(xlibSurface) {}
SharedSurface_GLXDrawable::~SharedSurface_GLXDrawable() = default;
GLContext* gl, const gfx::IntSize& size, bool inSameProcess,
const RefPtr<gfxXlibSurface>& xlibSurface)
: SharedSurface(SharedSurfaceType::GLXDrawable, AttachmentType::Screen, gl,
size, true, true),
mXlibSurface(xlibSurface),
mInSameProcess(inSameProcess) {}
void SharedSurface_GLXDrawable::ProducerReleaseImpl() {
mDesc.gl->MakeCurrent();
mDesc.gl->fFlush();
mGL->MakeCurrent();
mGL->fFlush();
}
void SharedSurface_GLXDrawable::LockProdImpl() {
GLContextGLX::Cast(mDesc.gl)->OverrideDrawable(mXlibSurface->GetGLXPixmap());
GLContextGLX::Cast(mGL)->OverrideDrawable(mXlibSurface->GetGLXPixmap());
}
void SharedSurface_GLXDrawable::UnlockProdImpl() {
GLContextGLX::Cast(mDesc.gl)->RestoreDrawable();
GLContextGLX::Cast(mGL)->RestoreDrawable();
}
Maybe<layers::SurfaceDescriptor>
SharedSurface_GLXDrawable::ToSurfaceDescriptor() {
if (!mXlibSurface) return {};
const bool sameProcess = false;
return Some(layers::SurfaceDescriptorX11(mXlibSurface, sameProcess));
bool SharedSurface_GLXDrawable::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
if (!mXlibSurface) return false;
*out_descriptor = layers::SurfaceDescriptorX11(mXlibSurface, mInSameProcess);
return true;
}
bool SharedSurface_GLXDrawable::ReadbackBySharedHandle(
@ -97,8 +96,25 @@ bool SharedSurface_GLXDrawable::ReadbackBySharedHandle(
return true;
}
SurfaceFactory_GLXDrawable::SurfaceFactory_GLXDrawable(GLContext& gl)
: SurfaceFactory({&gl, SharedSurfaceType::GLXDrawable,
layers::TextureType::X11, true}) {}
/* static */
UniquePtr<SurfaceFactory_GLXDrawable> SurfaceFactory_GLXDrawable::Create(
GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags) {
MOZ_ASSERT(caps.alpha, "GLX surfaces require an alpha channel!");
typedef SurfaceFactory_GLXDrawable ptrT;
UniquePtr<ptrT> ret(
new ptrT(prodGL, caps, allocator,
flags & ~layers::TextureFlags::ORIGIN_BOTTOM_LEFT));
return ret;
}
UniquePtr<SharedSurface> SurfaceFactory_GLXDrawable::CreateShared(
const gfx::IntSize& size) {
bool deallocateClient = !!(mFlags & layers::TextureFlags::DEALLOCATE_CLIENT);
return SharedSurface_GLXDrawable::Create(mGL, mCaps, size, deallocateClient,
mAllocator->IsSameProcess());
}
} // namespace mozilla::gl

Просмотреть файл

@ -14,18 +14,13 @@ class gfxXlibSurface;
namespace mozilla {
namespace gl {
class SharedSurface_GLXDrawable final : public SharedSurface {
class SharedSurface_GLXDrawable : public SharedSurface {
public:
const RefPtr<gfxXlibSurface> mXlibSurface;
static UniquePtr<SharedSurface_GLXDrawable> Create(const SharedSurfaceDesc&);
private:
SharedSurface_GLXDrawable(const SharedSurfaceDesc&,
const RefPtr<gfxXlibSurface>& xlibSurface);
public:
~SharedSurface_GLXDrawable();
static UniquePtr<SharedSurface_GLXDrawable> Create(GLContext* prodGL,
const SurfaceCaps& caps,
const gfx::IntSize& size,
bool deallocateClient,
bool inSameProcess);
virtual void ProducerAcquireImpl() override {}
virtual void ProducerReleaseImpl() override;
@ -33,18 +28,37 @@ class SharedSurface_GLXDrawable final : public SharedSurface {
virtual void LockProdImpl() override;
virtual void UnlockProdImpl() override;
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
virtual bool ReadbackBySharedHandle(
gfx::DataSourceSurface* out_surface) override;
private:
SharedSurface_GLXDrawable(GLContext* gl, const gfx::IntSize& size,
bool inSameProcess,
const RefPtr<gfxXlibSurface>& xlibSurface);
RefPtr<gfxXlibSurface> mXlibSurface;
bool mInSameProcess;
};
class SurfaceFactory_GLXDrawable final : public SurfaceFactory {
class SurfaceFactory_GLXDrawable : public SurfaceFactory {
public:
explicit SurfaceFactory_GLXDrawable(GLContext&);
static UniquePtr<SurfaceFactory_GLXDrawable> Create(
GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags);
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override;
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override;
private:
SurfaceFactory_GLXDrawable(GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags)
: SurfaceFactory(SharedSurfaceType::GLXDrawable, prodGL, caps, allocator,
flags) {}
};
} // namespace gl

Просмотреть файл

@ -6,7 +6,6 @@
#include "SharedSurfaceIO.h"
#include "GLContextCGL.h"
#include "MozFramebuffer.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/gfx/MacIOSurface.h"
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
@ -15,20 +14,107 @@
namespace mozilla {
namespace gl {
// -
// Factory
/*static*/
UniquePtr<SharedSurface_IOSurface> SharedSurface_IOSurface::Create(
const RefPtr<MacIOSurface>& ioSurf, GLContext* gl, bool hasAlpha) {
MOZ_ASSERT(ioSurf);
MOZ_ASSERT(gl);
SurfaceFactory_IOSurface::SurfaceFactory_IOSurface(GLContext& gl)
: SurfaceFactory({&gl, SharedSurfaceType::IOSurface,
layers::TextureType::MacIOSurface, true}),
mMaxDims(gfx::IntSize::Truncate(MacIOSurface::GetMaxWidth(),
MacIOSurface::GetMaxHeight())) {}
auto size = gfx::IntSize::Truncate(ioSurf->GetWidth(), ioSurf->GetHeight());
// -
// Surface
typedef SharedSurface_IOSurface ptrT;
UniquePtr<ptrT> ret(new ptrT(ioSurf, gl, size, hasAlpha));
return ret;
}
static void BackTextureWithIOSurf(GLContext* const gl, const GLuint tex,
MacIOSurface* const ioSurf) {
void SharedSurface_IOSurface::ProducerReleaseImpl() {
mGL->MakeCurrent();
mGL->fFlush();
}
bool SharedSurface_IOSurface::CopyTexImage2D(GLenum target, GLint level,
GLenum internalformat, GLint x,
GLint y, GLsizei width,
GLsizei height, GLint border) {
/* Bug 896693 - OpenGL framebuffers that are backed by IOSurface on OSX expose
* a bug in glCopyTexImage2D --- internalformats GL_ALPHA, GL_LUMINANCE,
* GL_LUMINANCE_ALPHA return the wrong results. To work around, copy
* framebuffer to a temporary texture using GL_RGBA (which works), attach as
* read framebuffer and glCopyTexImage2D instead.
*/
// https://www.opengl.org/sdk/docs/man3/xhtml/glCopyTexImage2D.xml says that
// width or height set to 0 results in a NULL texture. Lets not do any work
// and punt to original glCopyTexImage2D, since the FBO below will fail when
// trying to attach a texture of 0 width or height.
if (width == 0 || height == 0) return false;
switch (internalformat) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_LUMINANCE_ALPHA:
break;
default:
return false;
}
MOZ_ASSERT(mGL->IsCurrent());
ScopedTexture destTex(mGL);
{
ScopedBindTexture bindTex(mGL, destTex.Texture());
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_NEAREST);
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_NEAREST);
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, x, y, width,
height, 0);
}
ScopedFramebufferForTexture tmpFB(mGL, destTex.Texture(),
LOCAL_GL_TEXTURE_2D);
ScopedBindFramebuffer bindFB(mGL, tmpFB.FB());
mGL->raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height,
border);
return true;
}
bool SharedSurface_IOSurface::ReadPixels(GLint x, GLint y, GLsizei width,
GLsizei height, GLenum format,
GLenum type, GLvoid* pixels) {
// Calling glReadPixels when an IOSurface is bound to the current framebuffer
// can cause corruption in following glReadPixel calls (even if they aren't
// reading from an IOSurface).
// We workaround this by copying to a temporary texture, and doing the
// readback from that.
MOZ_ASSERT(mGL->IsCurrent());
ScopedTexture destTex(mGL);
{
ScopedFramebufferForTexture srcFB(mGL, ProdTexture(), ProdTextureTarget());
ScopedBindFramebuffer bindFB(mGL, srcFB.FB());
ScopedBindTexture bindTex(mGL, destTex.Texture());
mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
mHasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB, x, y,
width, height, 0);
}
ScopedFramebufferForTexture destFB(mGL, destTex.Texture());
ScopedBindFramebuffer bindFB(mGL, destFB.FB());
mGL->raw_fReadPixels(0, 0, width, height, format, type, pixels);
return true;
}
static void BackTextureWithIOSurf(GLContext* gl, GLuint tex,
MacIOSurface* ioSurf) {
MOZ_ASSERT(gl->IsCurrent());
ScopedBindTexture texture(gl, tex, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
@ -48,51 +134,31 @@ static void BackTextureWithIOSurf(GLContext* const gl, const GLuint tex,
ioSurf->CGLTexImageIOSurface2D(gl, cgl, 0);
}
/*static*/
UniquePtr<SharedSurface_IOSurface> SharedSurface_IOSurface::Create(
const SharedSurfaceDesc& desc) {
const auto& size = desc.size;
const RefPtr<MacIOSurface> ioSurf =
MacIOSurface::CreateIOSurface(size.width, size.height, 1.0, true);
if (!ioSurf) {
NS_WARNING("Failed to create MacIOSurface.");
return nullptr;
}
auto tex = MakeUnique<Texture>(*desc.gl);
BackTextureWithIOSurf(desc.gl, tex->name, ioSurf);
const GLenum target = LOCAL_GL_TEXTURE_RECTANGLE;
auto fb = MozFramebuffer::CreateForBacking(desc.gl, desc.size, 0, false,
target, tex->name);
if (!fb) return nullptr;
return AsUnique(
new SharedSurface_IOSurface(desc, std::move(fb), std::move(tex), ioSurf));
}
SharedSurface_IOSurface::SharedSurface_IOSurface(
const SharedSurfaceDesc& desc, UniquePtr<MozFramebuffer> fb,
UniquePtr<Texture> tex, const RefPtr<MacIOSurface>& ioSurf)
: SharedSurface(desc, std::move(fb)),
mTex(std::move(tex)),
mIOSurf(ioSurf) {}
SharedSurface_IOSurface::~SharedSurface_IOSurface() = default;
void SharedSurface_IOSurface::ProducerReleaseImpl() {
const auto& gl = mDesc.gl;
if (!gl) return;
const RefPtr<MacIOSurface>& ioSurf, GLContext* gl, const gfx::IntSize& size,
bool hasAlpha)
: SharedSurface(SharedSurfaceType::IOSurface, AttachmentType::GLTexture, gl,
size, hasAlpha, true),
mIOSurf(ioSurf) {
gl->MakeCurrent();
gl->fFlush();
mProdTex = 0;
gl->fGenTextures(1, &mProdTex);
BackTextureWithIOSurf(gl, mProdTex, mIOSurf);
}
Maybe<layers::SurfaceDescriptor>
SharedSurface_IOSurface::ToSurfaceDescriptor() {
const bool isOpaque = false; // RGBA
return Some(layers::SurfaceDescriptorMacIOSurface(
SharedSurface_IOSurface::~SharedSurface_IOSurface() {
if (!mGL || !mGL->MakeCurrent()) return;
mGL->fDeleteTextures(1, &mProdTex);
}
bool SharedSurface_IOSurface::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {
bool isOpaque = !mHasAlpha;
*out_descriptor = layers::SurfaceDescriptorMacIOSurface(
mIOSurf->GetIOSurfaceID(), mIOSurf->GetContentsScaleFactor(), isOpaque,
mIOSurf->GetYUVColorSpace()));
mIOSurf->GetYUVColorSpace());
return true;
}
bool SharedSurface_IOSurface::ReadbackBySharedHandle(
@ -120,5 +186,40 @@ bool SharedSurface_IOSurface::ReadbackBySharedHandle(
return true;
}
////////////////////////////////////////////////////////////////////////
// SurfaceFactory_IOSurface
/*static*/
UniquePtr<SurfaceFactory_IOSurface> SurfaceFactory_IOSurface::Create(
GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags) {
auto maxDims = gfx::IntSize::Truncate(MacIOSurface::GetMaxWidth(),
MacIOSurface::GetMaxHeight());
typedef SurfaceFactory_IOSurface ptrT;
UniquePtr<ptrT> ret(new ptrT(gl, caps, allocator, flags, maxDims));
return ret;
}
UniquePtr<SharedSurface> SurfaceFactory_IOSurface::CreateShared(
const gfx::IntSize& size) {
if (size.width > mMaxDims.width || size.height > mMaxDims.height) {
return nullptr;
}
bool hasAlpha = mReadCaps.alpha;
RefPtr<MacIOSurface> ioSurf;
ioSurf =
MacIOSurface::CreateIOSurface(size.width, size.height, 1.0, hasAlpha);
if (!ioSurf) {
NS_WARNING("Failed to create MacIOSurface.");
return nullptr;
}
return SharedSurface_IOSurface::Create(ioSurf, mGL, hasAlpha);
}
} // namespace gl
} // namespace mozilla

Просмотреть файл

@ -14,18 +14,18 @@ class MacIOSurface;
namespace mozilla {
namespace gl {
class Texture;
class SharedSurface_IOSurface final : public SharedSurface {
public:
const UniquePtr<Texture> mTex;
class SharedSurface_IOSurface : public SharedSurface {
private:
const RefPtr<MacIOSurface> mIOSurf;
GLuint mProdTex;
static UniquePtr<SharedSurface_IOSurface> Create(const SharedSurfaceDesc&);
public:
static UniquePtr<SharedSurface_IOSurface> Create(
const RefPtr<MacIOSurface>& ioSurf, GLContext* gl, bool hasAlpha);
private:
SharedSurface_IOSurface(const SharedSurfaceDesc&, UniquePtr<MozFramebuffer>,
UniquePtr<Texture>, const RefPtr<MacIOSurface>&);
SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf, GLContext* gl,
const gfx::IntSize& size, bool hasAlpha);
public:
~SharedSurface_IOSurface();
@ -36,9 +36,29 @@ class SharedSurface_IOSurface final : public SharedSurface {
virtual void ProducerAcquireImpl() override {}
virtual void ProducerReleaseImpl() override;
virtual bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border) override;
virtual bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid* pixels) override;
virtual GLuint ProdTexture() override { return mProdTex; }
virtual GLenum ProdTextureTarget() const override {
return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
}
static SharedSurface_IOSurface* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::IOSurface);
return static_cast<SharedSurface_IOSurface*>(surf);
}
MacIOSurface* GetIOSurface() const { return mIOSurf; }
virtual bool NeedsIndirectReads() const override { return true; }
Maybe<layers::SurfaceDescriptor> ToSurfaceDescriptor() override;
virtual bool ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) override;
virtual bool ReadbackBySharedHandle(
gfx::DataSourceSurface* out_surface) override;
@ -46,18 +66,25 @@ class SharedSurface_IOSurface final : public SharedSurface {
class SurfaceFactory_IOSurface : public SurfaceFactory {
public:
// Infallible.
static UniquePtr<SurfaceFactory_IOSurface> Create(
GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags);
protected:
const gfx::IntSize mMaxDims;
explicit SurfaceFactory_IOSurface(GLContext& gl);
SurfaceFactory_IOSurface(GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::LayersIPCChannel>& allocator,
const layers::TextureFlags& flags,
const gfx::IntSize& maxDims)
: SurfaceFactory(SharedSurfaceType::IOSurface, gl, caps, allocator,
flags),
mMaxDims(maxDims) {}
virtual UniquePtr<SharedSurface> CreateSharedImpl(
const SharedSurfaceDesc& desc) override {
if (desc.size.width > mMaxDims.width ||
desc.size.height > mMaxDims.height) {
return nullptr;
}
return SharedSurface_IOSurface::Create(desc);
}
virtual UniquePtr<SharedSurface> CreateShared(
const gfx::IntSize& size) override;
};
} // namespace gl

Просмотреть файл

@ -6,7 +6,9 @@
#ifndef SURFACE_TYPES_H_
#define SURFACE_TYPES_H_
#include <cstdint>
#include "mozilla/RefPtr.h"
#include "mozilla/Attributes.h"
#include <stdint.h>
namespace mozilla {
namespace layers {
@ -15,7 +17,58 @@ class LayersIPCChannel;
namespace gl {
struct SurfaceCaps final {
bool any = false;
bool color = false;
bool alpha = false;
bool bpp16 = false;
bool depth = false;
bool stencil = false;
bool premultAlpha = true;
bool preserve = false;
// The surface allocator that we want to create this
// for. May be null.
RefPtr<layers::LayersIPCChannel> surfaceAllocator;
SurfaceCaps();
SurfaceCaps(const SurfaceCaps& other);
~SurfaceCaps();
void Clear() { *this = {}; }
SurfaceCaps& operator=(const SurfaceCaps& other);
// We can't use just 'RGB' here, since it's an ancient Windows macro.
static SurfaceCaps ForRGB() {
SurfaceCaps caps;
caps.color = true;
return caps;
}
static SurfaceCaps ForRGBA() {
SurfaceCaps caps;
caps.color = true;
caps.alpha = true;
return caps;
}
static SurfaceCaps Any() {
SurfaceCaps caps;
caps.any = true;
return caps;
}
};
enum class SharedSurfaceType : uint8_t {
Unknown = 0,
Basic,
EGLImageShare,
EGLSurfaceANGLE,
@ -26,9 +79,21 @@ enum class SharedSurfaceType : uint8_t {
SharedGLTexture,
AndroidSurfaceTexture,
EGLSurfaceDMABUF,
Max
};
enum class AttachmentType : uint8_t {
Screen = 0,
GLTexture,
GLRenderbuffer,
Max
};
} // namespace gl
} // namespace mozilla
#endif // SURFACE_TYPES_H_
} /* namespace mozilla */
#endif /* SURFACE_TYPES_H_ */

Просмотреть файл

@ -0,0 +1,301 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "AsyncCanvasRenderer.h"
#include "gfxUtils.h"
#include "GLContext.h"
#include "GLReadTexImageHelper.h"
#include "GLScreenBuffer.h"
#include "Layers.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "nsICanvasRenderingContextInternal.h"
#include "mozilla/layers/BufferTexture.h"
#include "mozilla/layers/CanvasClient.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsIRunnable.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace layers {
AsyncCanvasRenderer::AsyncCanvasRenderer()
: mHTMLCanvasElement(nullptr),
mContext(nullptr),
mGLContext(nullptr),
mIsAlphaPremultiplied(true),
mWidth(0),
mHeight(0),
mCanvasClient(nullptr),
mMutex("AsyncCanvasRenderer::mMutex"),
mContextType(dom::CanvasContextType::NoContext) {
MOZ_COUNT_CTOR(AsyncCanvasRenderer);
}
AsyncCanvasRenderer::~AsyncCanvasRenderer() {
MOZ_COUNT_DTOR(AsyncCanvasRenderer);
}
void AsyncCanvasRenderer::NotifyElementAboutAttributesChanged() {
class Runnable final : public mozilla::Runnable {
public:
explicit Runnable(AsyncCanvasRenderer* aRenderer)
: mozilla::Runnable("Runnable"), mRenderer(aRenderer) {}
NS_IMETHOD Run() override {
if (mRenderer) {
dom::HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(mRenderer);
}
return NS_OK;
}
private:
RefPtr<AsyncCanvasRenderer> mRenderer;
};
nsCOMPtr<nsIRunnable> runnable = new Runnable(this);
nsresult rv = NS_DispatchToMainThread(runnable);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch a runnable to the main-thread.");
}
}
void AsyncCanvasRenderer::NotifyElementAboutInvalidation() {
class Runnable final : public mozilla::Runnable {
public:
explicit Runnable(AsyncCanvasRenderer* aRenderer)
: mozilla::Runnable("Runnable"), mRenderer(aRenderer) {}
NS_IMETHOD Run() override {
if (mRenderer) {
dom::HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(mRenderer);
}
return NS_OK;
}
private:
RefPtr<AsyncCanvasRenderer> mRenderer;
};
nsCOMPtr<nsIRunnable> runnable = new Runnable(this);
nsresult rv = NS_DispatchToMainThread(runnable);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch a runnable to the main-thread.");
}
}
void AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient) {
mCanvasClient = aClient;
if (aClient) {
mCanvasClientAsyncHandle = aClient->GetAsyncHandle();
if (mContext) {
MOZ_ASSERT(mCanvasClient->GetForwarder() &&
mCanvasClient->GetForwarder()->AsLayerForwarder() &&
mCanvasClient->GetForwarder()
->AsLayerForwarder()
->GetShadowManager());
LayerTransactionChild* ltc =
mCanvasClient->GetForwarder()->AsLayerForwarder()->GetShadowManager();
DebugOnly<bool> success =
mContext->UpdateCompositableHandle(ltc, mCanvasClientAsyncHandle);
MOZ_ASSERT(success);
}
} else {
mCanvasClientAsyncHandle = CompositableHandle();
}
}
void AsyncCanvasRenderer::SetActiveEventTarget() {
MutexAutoLock lock(mMutex);
mActiveEventTarget = GetCurrentThreadSerialEventTarget();
}
void AsyncCanvasRenderer::ResetActiveEventTarget() {
MutexAutoLock lock(mMutex);
mActiveEventTarget = nullptr;
}
already_AddRefed<nsISerialEventTarget>
AsyncCanvasRenderer::GetActiveEventTarget() {
MutexAutoLock lock(mMutex);
nsCOMPtr<nsISerialEventTarget> result = mActiveEventTarget;
return result.forget();
}
ImageContainer* AsyncCanvasRenderer::GetImageContainer() {
MOZ_ASSERT(mContextType == dom::CanvasContextType::ImageBitmap);
MutexAutoLock lock(mMutex);
if (!mImageContainer) {
mImageContainer =
LayerManager::CreateImageContainer(ImageContainer::ASYNCHRONOUS);
}
return mImageContainer;
}
dom::CanvasContextType AsyncCanvasRenderer::GetContextType() {
MutexAutoLock lock(mMutex);
return mContextType;
}
void AsyncCanvasRenderer::SetContextType(dom::CanvasContextType aContextType) {
MutexAutoLock lock(mMutex);
mContextType = aContextType;
}
void AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient) {
MutexAutoLock lock(mMutex);
if (!aTextureClient) {
mSurfaceForBasic = nullptr;
return;
}
TextureClientAutoLock texLock(aTextureClient, layers::OpenMode::OPEN_READ);
if (!texLock.Succeeded()) {
return;
}
const gfx::IntSize& size = aTextureClient->GetSize();
// This buffer would be used later for content rendering. So we choose
// B8G8R8A8 format here.
const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
// Avoid to create buffer every time.
if (!mSurfaceForBasic || size != mSurfaceForBasic->GetSize() ||
format != mSurfaceForBasic->GetFormat()) {
uint32_t stride =
gfx::GetAlignedStride<8>(size.width, BytesPerPixel(format));
mSurfaceForBasic =
gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
if (!mSurfaceForBasic) {
return;
}
}
MappedTextureData mapped;
if (!aTextureClient->BorrowMappedData(mapped)) {
return;
}
const uint8_t* lockedBytes = mapped.data;
gfx::DataSourceSurface::ScopedMap map(mSurfaceForBasic,
gfx::DataSourceSurface::MapType::WRITE);
if (!map.IsMapped()) {
return;
}
MOZ_ASSERT(map.GetStride() == mapped.stride);
memcpy(map.GetData(), lockedBytes,
map.GetStride() * mSurfaceForBasic->GetSize().height);
if (mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8A8 ||
mSurfaceForBasic->GetFormat() == gfx::SurfaceFormat::R8G8B8X8) {
gl::SwapRAndBComponents(mSurfaceForBasic);
}
}
already_AddRefed<gfx::DataSourceSurface> AsyncCanvasRenderer::UpdateTarget() {
if (!mGLContext) {
return nullptr;
}
gl::SharedSurface* frontbuffer = nullptr;
gl::GLScreenBuffer* screen = mGLContext->Screen();
const auto& front = screen->Front();
if (front) {
frontbuffer = front->Surf();
}
if (!frontbuffer) {
return nullptr;
}
if (frontbuffer->mType == gl::SharedSurfaceType::Basic) {
return nullptr;
}
const gfx::IntSize& size = frontbuffer->mSize;
// This buffer would be used later for content rendering. So we choose
// B8G8R8A8 format here.
const gfx::SurfaceFormat format = gfx::SurfaceFormat::B8G8R8A8;
uint32_t stride = gfx::GetAlignedStride<8>(size.width, BytesPerPixel(format));
RefPtr<gfx::DataSourceSurface> surface =
gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
if (NS_WARN_IF(!surface)) {
return nullptr;
}
if (!frontbuffer->ReadbackBySharedHandle(surface)) {
return nullptr;
}
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(surface, surface);
}
return surface.forget();
}
already_AddRefed<gfx::DataSourceSurface> AsyncCanvasRenderer::GetSurface() {
MOZ_ASSERT(NS_IsMainThread());
MutexAutoLock lock(mMutex);
if (mSurfaceForBasic) {
// Since SourceSurface isn't thread-safe, we need copy to a new
// SourceSurface.
gfx::DataSourceSurface::ScopedMap srcMap(mSurfaceForBasic,
gfx::DataSourceSurface::READ);
RefPtr<gfx::DataSourceSurface> result =
gfx::Factory::CreateDataSourceSurfaceWithStride(
mSurfaceForBasic->GetSize(), mSurfaceForBasic->GetFormat(),
srcMap.GetStride());
if (NS_WARN_IF(!result)) {
return nullptr;
}
gfx::DataSourceSurface::ScopedMap dstMap(result,
gfx::DataSourceSurface::WRITE);
if (NS_WARN_IF(!srcMap.IsMapped()) || NS_WARN_IF(!dstMap.IsMapped())) {
return nullptr;
}
memcpy(dstMap.GetData(), srcMap.GetData(),
srcMap.GetStride() * mSurfaceForBasic->GetSize().height);
return result.forget();
} else {
return UpdateTarget();
}
}
nsresult AsyncCanvasRenderer::GetInputStream(const char* aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream** aStream) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<gfx::DataSourceSurface> surface = GetSurface();
if (!surface) {
return NS_ERROR_FAILURE;
}
gfx::DataSourceSurface::ScopedMap map(surface, gfx::DataSourceSurface::READ);
// Handle y flip.
RefPtr<gfx::DataSourceSurface> dataSurf =
gl::YInvertImageSurface(surface, map.GetStride());
return gfxUtils::GetInputStream(dataSurf, false, aMimeType, aEncoderOptions,
aStream);
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,165 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_
#define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_
#include "LayersTypes.h"
#include "mozilla/dom/CanvasRenderingContextHelper.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/Mutex.h"
#include "nsCOMPtr.h" // for nsCOMPtr
class nsICanvasRenderingContextInternal;
class nsIInputStream;
class nsISerialEventTarget;
namespace mozilla {
namespace gfx {
class DataSourceSurface;
}
namespace gl {
class GLContext;
}
namespace dom {
class HTMLCanvasElement;
}
namespace layers {
class CanvasClient;
class TextureClient;
class ImageContainer;
/**
* Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create
* AsyncCanvasRenderer which is thread-safe wrapper object for communicating
* among main, worker and ImageBridgeChild threads.
*
* Each HTMLCanvasElement object is responsible for creating
* AsyncCanvasRenderer object. Once Canvas is transfered to worker,
* OffscreenCanvas will keep reference pointer of this object.
*
* Sometimes main thread needs AsyncCanvasRenderer's result, such as layers
* fallback to BasicLayerManager or calling toDataURL in Javascript. Simply call
* GetSurface() in main thread will readback the result to mSurface.
*
* If layers backend is LAYERS_CLIENT, this object will pass to ImageBridgeChild
* for submitting frames to Compositor.
*/
class AsyncCanvasRenderer final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncCanvasRenderer)
public:
AsyncCanvasRenderer();
void NotifyElementAboutAttributesChanged();
void NotifyElementAboutInvalidation();
void SetCanvasClient(CanvasClient* aClient);
void SetWidth(uint32_t aWidth) { mWidth = aWidth; }
void SetHeight(uint32_t aHeight) { mHeight = aHeight; }
void SetIsAlphaPremultiplied(bool aIsAlphaPremultiplied) {
mIsAlphaPremultiplied = aIsAlphaPremultiplied;
}
// Active thread means the thread which spawns GLContext.
void SetActiveEventTarget();
void ResetActiveEventTarget();
// This will readback surface and return the surface
// in the DataSourceSurface.
// Can be called in main thread only.
already_AddRefed<gfx::DataSourceSurface> GetSurface();
// For SharedSurface_Basic case, before the frame sending to the compositor,
// we readback it to a texture client because SharedSurface_Basic cannot
// shared. We don't want to readback it again here, so just copy the content
// of that texture client here to avoid readback again.
void CopyFromTextureClient(TextureClient* aClient);
// Readback current WebGL's content and convert it to InputStream. This
// function called GetSurface implicitly and GetSurface handles only get
// called in the main thread. So this function can be called in main thread.
nsresult GetInputStream(const char* aMimeType,
const nsAString& aEncoderOptions,
nsIInputStream** aStream);
gfx::IntSize GetSize() const { return gfx::IntSize(mWidth, mHeight); }
CompositableHandle GetCanvasClientAsyncHandle() const {
return mCanvasClientAsyncHandle;
}
CanvasClient* GetCanvasClient() const { return mCanvasClient; }
already_AddRefed<nsISerialEventTarget> GetActiveEventTarget();
ImageContainer* GetImageContainer();
dom::CanvasContextType GetContextType();
void SetContextType(dom::CanvasContextType aContextType);
// The lifetime is controllered by HTMLCanvasElement.
// Only accessed in main thread.
dom::HTMLCanvasElement* mHTMLCanvasElement;
// Only accessed in active thread.
nsICanvasRenderingContextInternal* mContext;
// We need to keep a reference to the context around here, otherwise the
// canvas' surface texture destructor will deref and destroy it too early
// Only accessed in active thread.
RefPtr<gl::GLContext> mGLContext;
private:
virtual ~AsyncCanvasRenderer();
// Readback current WebGL's content and return it as DataSourceSurface.
already_AddRefed<gfx::DataSourceSurface> UpdateTarget();
bool mIsAlphaPremultiplied;
uint32_t mWidth;
uint32_t mHeight;
CompositableHandle mCanvasClientAsyncHandle;
// The lifetime of this pointer is controlled by OffscreenCanvas
// Can be accessed in active thread and ImageBridge thread.
// But we never accessed it at the same time on both thread. So no
// need to protect this member.
CanvasClient* mCanvasClient;
// When backend is LAYER_BASIC and SharedSurface type is Basic.
// CanvasClient will readback the GLContext to a TextureClient
// in order to send frame to compositor. To avoid readback again,
// we copy from this TextureClient to this mSurfaceForBasic directly
// by calling CopyFromTextureClient().
RefPtr<gfx::DataSourceSurface> mSurfaceForBasic;
// Protect non thread-safe objects.
Mutex mMutex;
// Can be accessed in any thread, need protect by mutex.
nsCOMPtr<nsISerialEventTarget> mActiveEventTarget;
// Can be accessed in any thread, need protect by mutex.
RefPtr<ImageContainer> mImageContainer;
// Can be accessed in any thread, need protect by mutex.
dom::CanvasContextType mContextType;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_

Просмотреть файл

@ -6,77 +6,38 @@
#include "CanvasRenderer.h"
#include "nsICanvasRenderingContextInternal.h"
#include "AsyncCanvasRenderer.h"
#include "GLContext.h"
#include "OOPCanvasRenderer.h"
#include "PersistentBufferProvider.h"
#include "WebGLTypes.h"
namespace mozilla {
namespace layers {
CanvasRendererData::CanvasRendererData() = default;
CanvasRendererData::~CanvasRendererData() = default;
CanvasInitializeData::CanvasInitializeData() = default;
CanvasInitializeData::~CanvasInitializeData() = default;
// -
BorrowedSourceSurface::BorrowedSourceSurface(
PersistentBufferProvider* const returnTo,
const RefPtr<gfx::SourceSurface> surf)
: mReturnTo(returnTo), mSurf(surf) {}
BorrowedSourceSurface::~BorrowedSourceSurface() {
if (mReturnTo) {
auto forgettable = mSurf;
mReturnTo->ReturnSnapshot(forgettable.forget());
}
CanvasRenderer::CanvasRenderer()
: mPreTransCallback(nullptr),
mPreTransCallbackData(nullptr),
mDidTransCallback(nullptr),
mDidTransCallbackData(nullptr),
mDirty(false) {
MOZ_COUNT_CTOR(CanvasRenderer);
}
// -
CanvasRenderer::CanvasRenderer() { MOZ_COUNT_CTOR(CanvasRenderer); }
CanvasRenderer::~CanvasRenderer() {
Destroy();
MOZ_COUNT_DTOR(CanvasRenderer);
}
void CanvasRenderer::Initialize(const CanvasRendererData& aData) {
mData = aData;
}
void CanvasRenderer::Initialize(const CanvasInitializeData& aData) {
mPreTransCallback = aData.mPreTransCallback;
mPreTransCallbackData = aData.mPreTransCallbackData;
mDidTransCallback = aData.mDidTransCallback;
mDidTransCallbackData = aData.mDidTransCallbackData;
bool CanvasRenderer::IsDataValid(const CanvasRendererData& aData) const {
return mData.GetContext() == aData.GetContext();
}
std::shared_ptr<BorrowedSourceSurface> CanvasRenderer::BorrowSnapshot(
const bool requireAlphaPremult) const {
const auto context = mData.GetContext();
if (!context) return nullptr;
const auto& provider = context->GetBufferProvider();
RefPtr<gfx::SourceSurface> ss;
if (provider) {
ss = provider->BorrowSnapshot();
}
if (!ss) {
ss = context->GetFrontBufferSnapshot(requireAlphaPremult);
}
if (!ss) return nullptr;
return std::make_shared<BorrowedSourceSurface>(provider, ss);
}
void CanvasRenderer::FirePreTransactionCallback() const {
if (!mData.mDoPaintCallbacks) return;
const auto context = mData.GetContext();
if (!context) return;
context->OnBeforePaintTransaction();
}
void CanvasRenderer::FireDidTransactionCallback() const {
if (!mData.mDoPaintCallbacks) return;
const auto context = mData.GetContext();
if (!context) return;
context->OnDidPaintTransaction();
mSize = aData.mSize;
}
} // namespace layers

Просмотреть файл

@ -7,7 +7,6 @@
#ifndef GFX_CANVASRENDERER_H
#define GFX_CANVASRENDERER_H
#include <memory> // for weak_ptr
#include <stdint.h> // for uint32_t
#include "GLContextTypes.h" // for GLContext
#include "gfxContext.h" // for gfxContext, etc
@ -18,63 +17,75 @@
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "mozilla/WeakPtr.h" // for WeakPtr
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
class nsICanvasRenderingContextInternal;
namespace mozilla {
namespace layers {
class AsyncCanvasRenderer;
class ClientCanvasRenderer;
class CopyableCanvasRenderer;
class OOPCanvasRenderer;
class PersistentBufferProvider;
class WebRenderCanvasRendererAsync;
struct CanvasRendererData final {
CanvasRendererData();
~CanvasRendererData();
struct CanvasInitializeData final {
CanvasInitializeData();
~CanvasInitializeData();
std::weak_ptr<nsICanvasRenderingContextInternal* const>
mContext; // weak_ptr to ptr (bug 1635644)
// One of these four must be specified for Canvas2D, but never more than one
RefPtr<PersistentBufferProvider>
mBufferProvider; // A BufferProvider for the Canvas contents
RefPtr<mozilla::gl::GLContext> mGLContext; // or this, for GL.
RefPtr<AsyncCanvasRenderer> mRenderer; // or this, for OffscreenCanvas
RefPtr<OOPCanvasRenderer> mOOPRenderer; // or this, for WebGL in host process
typedef void (*TransactionCallback)(void* closureData);
TransactionCallback mPreTransCallback = nullptr;
void* mPreTransCallbackData = nullptr;
TransactionCallback mDidTransCallback = nullptr;
void* mDidTransCallbackData = nullptr;
// The size of the canvas content
gfx::IntSize mSize = {0, 0};
bool mDoPaintCallbacks = false;
bool mIsOpaque = true;
bool mIsAlphaPremult = true;
// Whether the canvas drawingbuffer has an alpha channel.
bool mHasAlpha = false;
gl::OriginPos mOriginPos = gl::OriginPos::TopLeft;
nsICanvasRenderingContextInternal* GetContext() const {
const auto ptrToPtr = mContext.lock();
if (!ptrToPtr) return nullptr;
return *ptrToPtr;
}
// Whether mGLContext contains data that is alpha-premultiplied.
bool mIsGLAlphaPremult = true;
};
// Based class which used for canvas rendering. There are many derived classes
// for different purposes. such as:
//
// CopyableCanvasRenderer provides a utility which readback canvas content to a
// SourceSurface. BasicCanvasLayer uses CopyableCanvasRenderer.
//
// ShareableCanvasRenderer provides IPC capabilities that allow sending canvas
// content over IPC. This is pure virtual class because the IPC handling is
// different in different LayerManager. So that we have following classes
// inherit ShareableCanvasRenderer.
// inherite ShareableCanvasRenderer.
//
// ClientCanvasRenderer inherits ShareableCanvasRenderer and be used in
// ClientCanvasRenderer inherites ShareableCanvasRenderer and be used in
// ClientCanvasLayer.
// WebRenderCanvasRenderer inherits ShareableCanvasRenderer and provides all
// WebRenderCanvasRenderer inherites ShareableCanvasRenderer and provides all
// functionality that WebRender uses.
// WebRenderCanvasRendererAsync inherits WebRenderCanvasRenderer and be used in
// WebRenderCanvasRendererAsync inherites WebRenderCanvasRenderer and be used in
// layers-free mode of WebRender.
//
// class diagram:
// class diagram shows below:
//
// +--------------+
// |CanvasRenderer|
// +-------+------+
// ^
// |
// +----------------------+
// |CopyableCanvasRenderer|
// +----------------------+
// ^
// |
// +-----------+-----------+
// |ShareableCanvasRenderer|
// +-----+-----------------+
@ -89,60 +100,55 @@ struct CanvasRendererData final {
// +-------------+--------------+
// |WebRenderCanvasRendererAsync|
// +----------------------------+
class BorrowedSourceSurface final {
class CanvasRenderer {
public:
PersistentBufferProvider* const mReturnTo;
const RefPtr<gfx::SourceSurface> mSurf; /// non-null
BorrowedSourceSurface(PersistentBufferProvider*, RefPtr<gfx::SourceSurface>);
~BorrowedSourceSurface();
};
// -
class CanvasRenderer : public RefCounted<CanvasRenderer> {
friend class CanvasRendererSourceSurface;
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(CanvasRenderer)
private:
bool mDirty = false;
protected:
CanvasRendererData mData;
public:
explicit CanvasRenderer();
CanvasRenderer();
virtual ~CanvasRenderer();
public:
virtual void Initialize(const CanvasRendererData&);
virtual bool IsDataValid(const CanvasRendererData&) const;
virtual void Initialize(const CanvasInitializeData& aData);
virtual bool IsDataValid(const CanvasInitializeData& aData) { return true; }
virtual void ClearCachedResources() {}
virtual void DisconnectClient() {}
virtual void Destroy() {}
const gfx::IntSize& GetSize() const { return mData.mSize; }
bool IsOpaque() const { return mData.mIsOpaque; }
bool YIsDown() const { return mData.mOriginPos == gl::OriginPos::TopLeft; }
const gfx::IntSize& GetSize() const { return mSize; }
void SetDirty() { mDirty = true; }
void ResetDirty() { mDirty = false; }
bool IsDirty() const { return mDirty; }
virtual CopyableCanvasRenderer* AsCopyableCanvasRenderer() { return nullptr; }
virtual ClientCanvasRenderer* AsClientCanvasRenderer() { return nullptr; }
virtual WebRenderCanvasRendererAsync* AsWebRenderCanvasRendererAsync() {
return nullptr;
}
std::shared_ptr<BorrowedSourceSurface> BorrowSnapshot(
bool requireAlphaPremult = true) const;
protected:
void FirePreTransactionCallback() const;
void FireDidTransactionCallback() const;
void FirePreTransactionCallback() {
if (mPreTransCallback) {
mPreTransCallback(mPreTransCallbackData);
}
}
void FireDidTransactionCallback() {
if (mDidTransCallback) {
mDidTransCallback(mDidTransCallbackData);
}
}
typedef void (*TransactionCallback)(void* closureData);
TransactionCallback mPreTransCallback;
void* mPreTransCallbackData;
TransactionCallback mDidTransCallback;
void* mDidTransCallbackData;
gfx::IntSize mSize;
private:
/**
* Set to true in Updated(), cleared during a transaction.
*/
bool mDirty;
};
} // namespace layers

Просмотреть файл

@ -0,0 +1,183 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "CopyableCanvasRenderer.h"
#include "BasicLayersImpl.h" // for FillWithMask, etc
#include "GLContext.h" // for GLContext
#include "GLScreenBuffer.h" // for GLScreenBuffer
#include "OOPCanvasRenderer.h" // for OOPCanvasRenderer
#include "SharedSurface.h" // for SharedSurface
#include "SharedSurfaceGL.h" // for SharedSurface
#include "gfxPattern.h" // for gfxPattern, etc
#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
#include "gfxRect.h" // for gfxRect
#include "gfxUtils.h" // for gfxUtils
#include "gfx2DGlue.h" // for thebes --> moz2d transition
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Tools.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/PersistentBufferProvider.h"
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
#include "nsRect.h" // for mozilla::gfx::IntRect
#include "gfxUtils.h"
#include "client/TextureClientSharedSurface.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
using namespace mozilla::gl;
CopyableCanvasRenderer::CopyableCanvasRenderer()
: mGLContext(nullptr),
mBufferProvider(nullptr),
mAsyncRenderer(nullptr),
mIsAlphaPremultiplied(true),
mOriginPos(gl::OriginPos::TopLeft),
mOpaque(true),
mCachedTempSurface(nullptr) {
MOZ_COUNT_CTOR(CopyableCanvasRenderer);
}
CopyableCanvasRenderer::~CopyableCanvasRenderer() {
Destroy();
MOZ_COUNT_DTOR(CopyableCanvasRenderer);
}
void CopyableCanvasRenderer::Initialize(const CanvasInitializeData& aData) {
CanvasRenderer::Initialize(aData);
if (aData.mGLContext) {
if (aData.mGLContext->IsDestroyed()) {
return;
}
mGLContext = aData.mGLContext;
mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
mOriginPos = gl::OriginPos::BottomLeft;
MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
} else if (aData.mBufferProvider) {
mBufferProvider = aData.mBufferProvider;
} else if (aData.mRenderer) {
mAsyncRenderer = aData.mRenderer;
mOriginPos = gl::OriginPos::BottomLeft;
} else if (aData.mOOPRenderer) {
mOOPRenderer = aData.mOOPRenderer;
}
mOpaque = !aData.mHasAlpha;
}
bool CopyableCanvasRenderer::IsDataValid(const CanvasInitializeData& aData) {
return mGLContext == aData.mGLContext &&
mBufferProvider == aData.mBufferProvider &&
mOOPRenderer == aData.mOOPRenderer;
}
void CopyableCanvasRenderer::ClearCachedResources() {
SetDirty();
if (mBufferProvider) {
mBufferProvider->ClearCachedResources();
}
mCachedTempSurface = nullptr;
}
void CopyableCanvasRenderer::Destroy() {
if (mBufferProvider) {
mBufferProvider->ClearCachedResources();
}
mBufferProvider = nullptr;
mCachedTempSurface = nullptr;
}
already_AddRefed<SourceSurface> CopyableCanvasRenderer::ReadbackSurface() {
struct ScopedFireTransactionCallback {
explicit ScopedFireTransactionCallback(CopyableCanvasRenderer* aRenderer)
: mRenderer(aRenderer) {
mRenderer->FirePreTransactionCallback();
}
~ScopedFireTransactionCallback() {
mRenderer->FireDidTransactionCallback();
}
CopyableCanvasRenderer* mRenderer;
};
ScopedFireTransactionCallback callback(this);
if (mAsyncRenderer) {
MOZ_ASSERT(!mBufferProvider);
MOZ_ASSERT(!mGLContext);
return mAsyncRenderer->GetSurface();
}
if (!mGLContext) {
return nullptr;
}
SharedSurface* frontbuffer = nullptr;
if (mGLContext->Screen()) {
const auto& front = mGLContext->Screen()->Front();
if (front) {
frontbuffer = front->Surf();
}
}
if (!frontbuffer) {
NS_WARNING("Null frame received.");
return nullptr;
}
IntSize readSize(frontbuffer->mSize);
SurfaceFormat format = frontbuffer->mHasAlpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8;
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
// There will already be a warning from inside of GetTempSurface, but
// it doesn't hurt to complain:
if (NS_WARN_IF(!resultSurf)) {
return nullptr;
}
// Readback handles Flush/MarkDirty.
if (!mGLContext->Readback(frontbuffer, resultSurf)) {
NS_WARNING("Failed to read back canvas surface.");
return nullptr;
}
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
}
MOZ_ASSERT(resultSurf);
return resultSurf.forget();
}
DataSourceSurface* CopyableCanvasRenderer::GetTempSurface(
const IntSize& aSize, const SurfaceFormat aFormat) {
MOZ_ASSERT(!mOOPRenderer);
if (!mCachedTempSurface || aSize != mCachedTempSurface->GetSize() ||
aFormat != mCachedTempSurface->GetFormat()) {
// Create a surface aligned to 8 bytes since that's the highest alignment
// WebGL can handle.
uint32_t stride = GetAlignedStride<8>(aSize.width, BytesPerPixel(aFormat));
mCachedTempSurface =
Factory::CreateDataSourceSurfaceWithStride(aSize, aFormat, stride);
}
return mCachedTempSurface;
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef GFX_COPYABLECANVASRENDERER_H
#define GFX_COPYABLECANVASRENDERER_H
#include <stdint.h> // for uint32_t
#include "CanvasRenderer.h"
#include "GLContextTypes.h" // for GLContext
#include "gfxContext.h" // for gfxContext, etc
#include "gfxTypes.h"
#include "gfxPlatform.h" // for gfxImageFormat
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Preferences.h" // for Preferences
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
namespace mozilla {
namespace gl {
class SharedSurface;
} // namespace gl
namespace layers {
/**
* A shared CanvasRenderer implementation that supports copying
* its contents into a gfxASurface using RebackSurface.
*/
class CopyableCanvasRenderer : public CanvasRenderer {
public:
CopyableCanvasRenderer();
virtual ~CopyableCanvasRenderer();
public:
void Initialize(const CanvasInitializeData& aData) override;
bool IsDataValid(const CanvasInitializeData& aData) override;
void ClearCachedResources() override;
void Destroy() override;
CopyableCanvasRenderer* AsCopyableCanvasRenderer() override { return this; }
bool NeedsYFlip() const { return mOriginPos == gl::OriginPos::BottomLeft; }
bool HasGLContext() const { return !!mGLContext; }
bool IsOpaque() const { return mOpaque; }
PersistentBufferProvider* GetBufferProvider() { return mBufferProvider; }
already_AddRefed<gfx::SourceSurface> ReadbackSurface();
protected:
RefPtr<gl::GLContext> mGLContext;
RefPtr<PersistentBufferProvider> mBufferProvider;
RefPtr<AsyncCanvasRenderer> mAsyncRenderer;
RefPtr<OOPCanvasRenderer> mOOPRenderer;
bool mIsAlphaPremultiplied;
gl::OriginPos mOriginPos;
bool mOpaque;
RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize,
const gfx::SurfaceFormat aFormat);
};
} // namespace layers
} // namespace mozilla
#endif

Просмотреть файл

@ -26,7 +26,8 @@ already_AddRefed<gfx::SourceSurface> GLImage::GetAsSourceSurface() {
if (!sSnapshotContext) {
nsCString discardFailureId;
sSnapshotContext = GLContextProvider::CreateHeadless({}, &discardFailureId);
sSnapshotContext = GLContextProvider::CreateHeadless(
CreateContextFlags::NONE, &discardFailureId);
if (!sSnapshotContext) {
NS_WARNING("Failed to create snapshot GLContext");
return nullptr;

Просмотреть файл

@ -28,6 +28,7 @@
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/gfx/Polygon.h" // for Polygon
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/BSPTree.h" // for BSPTree
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
#include "mozilla/layers/Compositor.h" // for Compositor
@ -2044,12 +2045,12 @@ void CanvasLayer::DumpPacket(layerscope::LayersPacket* aPacket,
DumpFilter(layer, mSamplingFilter);
}
RefPtr<CanvasRenderer> CanvasLayer::CreateOrGetCanvasRenderer() {
CanvasRenderer* CanvasLayer::CreateOrGetCanvasRenderer() {
if (!mCanvasRenderer) {
mCanvasRenderer = CreateCanvasRendererInternal();
mCanvasRenderer.reset(CreateCanvasRendererInternal());
}
return mCanvasRenderer;
return mCanvasRenderer.get();
}
void ImageLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix) {

Просмотреть файл

@ -77,6 +77,7 @@ class DrawTarget;
namespace layers {
class Animation;
class AsyncCanvasRenderer;
class AsyncPanZoomController;
class BasicLayerManager;
class ClientLayerManager;
@ -2539,7 +2540,7 @@ class CanvasLayer : public Layer {
const nsIntRect& GetBounds() const { return mBounds; }
RefPtr<CanvasRenderer> CreateOrGetCanvasRenderer();
CanvasRenderer* CreateOrGetCanvasRenderer();
public:
/**
@ -2580,9 +2581,9 @@ class CanvasLayer : public Layer {
void DumpPacket(layerscope::LayersPacket* aPacket,
const void* aParent) override;
virtual RefPtr<CanvasRenderer> CreateCanvasRendererInternal() = 0;
virtual CanvasRenderer* CreateCanvasRendererInternal() = 0;
RefPtr<CanvasRenderer> mCanvasRenderer;
UniquePtr<CanvasRenderer> mCanvasRenderer;
gfx::SamplingFilter mSamplingFilter;
/**

Просмотреть файл

@ -167,7 +167,6 @@ enum class TextureType : int8_t {
MacIOSurface,
AndroidNativeWindow,
WaylandDMABUF,
EGLImage,
Last
};

Просмотреть файл

@ -263,8 +263,8 @@ void NativeLayerRootCA::Representation::Commit(WhichRepresentation aRepresentati
nsCString failureUnused;
RefPtr<gl::GLContext> gl =
gl::GLContextProvider::CreateHeadless({gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE},
gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE,
&failureUnused);
if (!gl) {
return nullptr;

Просмотреть файл

@ -6,80 +6,185 @@
#include "ShareableCanvasRenderer.h"
#include "mozilla/dom/WebGLTypes.h"
#include "GLContext.h" // for GLContext
#include "GLScreenBuffer.h" // for GLScreenBuffer
#include "SharedSurfaceGL.h" // for SurfaceFactory_GLTexture, etc
#include "gfxUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "ClientWebGLContext.h"
#include "gfxUtils.h"
#include "GLScreenBuffer.h"
#include "nsICanvasRenderingContextInternal.h"
#include "SharedSurfaceGL.h"
using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
ShareableCanvasRenderer::ShareableCanvasRenderer() {
ShareableCanvasRenderer::ShareableCanvasRenderer()
: mCanvasClient(nullptr),
mFactory(nullptr),
mFlags(TextureFlags::NO_FLAGS) {
MOZ_COUNT_CTOR(ShareableCanvasRenderer);
}
ShareableCanvasRenderer::~ShareableCanvasRenderer() {
MOZ_COUNT_DTOR(ShareableCanvasRenderer);
mFrontBufferFromDesc = nullptr;
DisconnectClient();
Destroy();
}
void ShareableCanvasRenderer::Initialize(const CanvasRendererData& aData) {
CanvasRenderer::Initialize(aData);
void ShareableCanvasRenderer::Initialize(const CanvasInitializeData& aData) {
CopyableCanvasRenderer::Initialize(aData);
mCanvasClient = nullptr;
if (!mGLContext) return;
gl::GLScreenBuffer* screen = mGLContext->Screen();
MOZ_ASSERT(screen);
gl::SurfaceCaps caps = screen->mCaps;
auto forwarder = GetForwarder();
mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT;
if (!aData.mIsGLAlphaPremult) {
mFlags |= TextureFlags::NON_PREMULTIPLIED;
}
if (!aData.mHasAlpha) {
mFlags |= TextureFlags::IS_OPAQUE;
}
UniquePtr<gl::SurfaceFactory> factory =
gl::GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags);
if (factory) {
screen->Morph(std::move(factory));
}
}
void ShareableCanvasRenderer::ClearCachedResources() {
CanvasRenderer::ClearCachedResources();
CopyableCanvasRenderer::ClearCachedResources();
if (mCanvasClient) {
mCanvasClient->Clear();
}
}
void ShareableCanvasRenderer::DisconnectClient() {
void ShareableCanvasRenderer::Destroy() {
CopyableCanvasRenderer::Destroy();
if (mCanvasClient) {
mCanvasClient->OnDetach();
mCanvasClient = nullptr;
}
}
RefPtr<layers::TextureClient> ShareableCanvasRenderer::GetFrontBufferFromDesc(
const layers::SurfaceDescriptor& desc, TextureFlags flags) {
if (mFrontBufferFromDesc && mFrontBufferDesc == desc)
return mFrontBufferFromDesc;
mFrontBufferFromDesc = nullptr;
bool ShareableCanvasRenderer::UpdateTarget(DrawTarget* aDestTarget) {
MOZ_ASSERT(!mOOPRenderer);
// Test the validity of aAllocator
const auto& compositableForwarder = GetForwarder();
if (!compositableForwarder) {
return nullptr;
MOZ_ASSERT(aDestTarget);
if (!aDestTarget) {
return false;
}
const auto& textureForwarder = compositableForwarder->GetTextureForwarder();
auto format = gfx::SurfaceFormat::R8G8B8X8;
if (!mData.mIsOpaque) {
format = gfx::SurfaceFormat::R8G8B8A8;
RefPtr<SourceSurface> surface;
if (!mData.mIsAlphaPremult) {
flags |= TextureFlags::NON_PREMULTIPLIED;
if (!mGLContext) {
AutoReturnSnapshot autoReturn;
if (mAsyncRenderer) {
surface = mAsyncRenderer->GetSurface();
} else if (mBufferProvider) {
surface = mBufferProvider->BorrowSnapshot();
autoReturn.mSnapshot = &surface;
autoReturn.mBufferProvider = mBufferProvider;
}
MOZ_ASSERT(surface);
if (!surface) {
return false;
}
aDestTarget->CopySurface(surface, IntRect(0, 0, mSize.width, mSize.height),
IntPoint(0, 0));
return true;
}
auto data = MakeUnique<SharedSurfaceTextureData>(desc, format, mData.mSize);
mFrontBufferDesc = desc;
mFrontBufferFromDesc =
TextureClient::CreateWithData(data.release(), flags, textureForwarder);
return mFrontBufferFromDesc;
gl::SharedSurface* frontbuffer = nullptr;
gl::GLScreenBuffer* screen = mGLContext->Screen();
const auto& front = screen->Front();
if (front) {
frontbuffer = front->Surf();
}
if (!frontbuffer) {
NS_WARNING("Null frame received.");
return false;
}
IntSize readSize(frontbuffer->mSize);
SurfaceFormat format =
mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
// Try to read back directly into aDestTarget's output buffer
uint8_t* destData;
IntSize destSize;
int32_t destStride;
SurfaceFormat destFormat;
if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
if (destSize == readSize && destFormat == format) {
RefPtr<DataSourceSurface> data = Factory::CreateWrappingDataSourceSurface(
destData, destStride, destSize, destFormat);
if (!mGLContext->Readback(frontbuffer, data)) {
aDestTarget->ReleaseBits(destData);
return false;
}
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(data, data);
}
aDestTarget->ReleaseBits(destData);
return true;
}
aDestTarget->ReleaseBits(destData);
}
RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
// There will already be a warning from inside of GetTempSurface, but
// it doesn't hurt to complain:
if (NS_WARN_IF(!resultSurf)) {
return false;
}
// Readback handles Flush/MarkDirty.
if (!mGLContext->Readback(frontbuffer, resultSurf)) {
return false;
}
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
}
aDestTarget->CopySurface(resultSurf,
IntRect(0, 0, readSize.width, readSize.height),
IntPoint(0, 0));
return true;
}
CanvasClient::CanvasClientType ShareableCanvasRenderer::GetCanvasClientType() {
if (mAsyncRenderer) {
return CanvasClient::CanvasClientAsync;
}
if (mGLContext) {
return CanvasClient::CanvasClientTypeShSurf;
}
if (mOOPRenderer) {
return CanvasClient::CanvasClientTypeOOP;
}
return CanvasClient::CanvasClientSurface;
}
void ShareableCanvasRenderer::UpdateCompositableClient() {
@ -87,112 +192,29 @@ void ShareableCanvasRenderer::UpdateCompositableClient() {
return;
}
if (mCanvasClient && mAsyncRenderer) {
mCanvasClient->UpdateAsync(mAsyncRenderer);
}
if (!IsDirty()) {
return;
}
ResetDirty();
const auto context = mData.GetContext();
if (!context) return;
const auto& provider = context->GetBufferProvider();
const auto webgl = context->AsWebgl();
const auto& forwarder = GetForwarder();
// -
auto flags = TextureFlags::IMMUTABLE;
if (!YIsDown()) {
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
}
// -
const auto fnGetExistingTc = [&]() -> RefPtr<TextureClient> {
if (provider) {
auto tc = provider->GetTextureClient();
if (!tc) return nullptr;
if (!provider->SetKnowsCompositor(forwarder)) {
gfxCriticalNote << "BufferProvider::SetForwarder failed";
return nullptr;
}
tc = provider->GetTextureClient(); // Ask again after SetKnowsCompositor
return tc;
}
if (!webgl) return nullptr;
if (!forwarder) return nullptr;
auto texType = layers::TextureType::Unknown;
if (forwarder) {
texType = layers::PreferredCanvasTextureType(*forwarder);
}
const auto desc = webgl->GetFrontBuffer(nullptr, texType);
if (!desc) return nullptr;
return GetFrontBufferFromDesc(*desc, flags);
};
// -
const auto fnMakeTcFromSnapshot = [&]() -> RefPtr<TextureClient> {
const auto& size = mData.mSize;
auto contentType = gfxContentType::COLOR;
if (!mData.mIsOpaque) {
contentType = gfxContentType::COLOR_ALPHA;
}
const auto surfaceFormat =
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType);
const auto tc =
mCanvasClient->CreateTextureClientForCanvas(surfaceFormat, size, flags);
if (!tc) {
return nullptr;
}
{
TextureClientAutoLock tcLock(tc, OpenMode::OPEN_WRITE_ONLY);
if (!tcLock.Succeeded()) {
return nullptr;
}
const RefPtr<DrawTarget> dt = tc->BorrowDrawTarget();
const bool requireAlphaPremult = false;
const auto borrowed = BorrowSnapshot(requireAlphaPremult);
if (!borrowed) return nullptr;
dt->CopySurface(borrowed->mSurf, {{0, 0}, size}, {0, 0});
}
return tc;
};
// -
{
FirePreTransactionCallback();
// First, let's see if we can get a no-copy TextureClient from the canvas.
auto tc = fnGetExistingTc();
if (!tc) {
// Otherwise, snapshot the surface and copy into a TexClient.
tc = fnMakeTcFromSnapshot();
}
if (tc != mFrontBufferFromDesc) {
mFrontBufferFromDesc = nullptr;
}
if (!tc) {
NS_WARNING("Couldn't make TextureClient for CanvasRenderer.");
FirePreTransactionCallback();
if (mBufferProvider && mBufferProvider->GetTextureClient()) {
if (!mBufferProvider->SetKnowsCompositor(GetForwarder())) {
gfxCriticalNote << "BufferProvider::SetForwarder failed";
return;
}
mCanvasClient->UseTexture(tc);
FireDidTransactionCallback();
mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient());
} else {
mCanvasClient->Update(gfx::IntSize(mSize.width, mSize.height), this);
}
FireDidTransactionCallback();
mCanvasClient->Updated();
}
} // namespace layers

Просмотреть файл

@ -8,7 +8,7 @@
#define GFX_SHAREABLECANVASRENDERER_H
#include "CompositorTypes.h"
#include "CanvasRenderer.h"
#include "CopyableCanvasRenderer.h"
#include "mozilla/layers/CanvasClient.h"
namespace mozilla {
@ -22,38 +22,42 @@ class DrawTarget;
namespace layers {
class ShareableCanvasRenderer : public CanvasRenderer {
friend class CanvasClient2D;
friend class CanvasClientSharedSurface;
protected:
RefPtr<CanvasClient> mCanvasClient;
private:
layers::SurfaceDescriptor mFrontBufferDesc;
RefPtr<TextureClient> mFrontBufferFromDesc;
class ShareableCanvasRenderer : public CopyableCanvasRenderer {
typedef CanvasClient::CanvasClientType CanvasClientType;
public:
ShareableCanvasRenderer();
virtual ~ShareableCanvasRenderer();
public:
void Initialize(const CanvasRendererData&) override;
void Initialize(const CanvasInitializeData& aData) override;
virtual CompositableForwarder* GetForwarder() = 0;
virtual bool CreateCompositable() = 0;
void ClearCachedResources() override;
void DisconnectClient() override;
void Destroy() override;
void UpdateCompositableClient();
const TextureFlags& Flags() const { return mFlags; }
CanvasClient* GetCanvasClient() { return mCanvasClient; }
private:
RefPtr<TextureClient> GetFrontBufferFromDesc(const layers::SurfaceDescriptor&,
TextureFlags);
protected:
bool UpdateTarget(gfx::DrawTarget* aDestTarget);
CanvasClientType GetCanvasClientType();
RefPtr<CanvasClient> mCanvasClient;
UniquePtr<gl::SurfaceFactory> mFactory;
TextureFlags mFlags;
friend class CanvasClient2D;
friend class CanvasClientSharedSurface;
};
} // namespace layers

Просмотреть файл

@ -4,15 +4,11 @@
* 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 "APZThreadUtils.h"
#include "mozilla/layers/APZThreadUtils.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticMutex.h"
#include "nsISerialEventTarget.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace layers {

Просмотреть файл

@ -9,9 +9,6 @@
#include "nsINamed.h"
#include "nsITimer.h"
#include "nsString.h"
class nsISerialEventTarget;
namespace mozilla {

Просмотреть файл

@ -5,11 +5,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BasicCanvasLayer.h"
#include "AsyncCanvasRenderer.h"
#include "basic/BasicLayers.h" // for BasicLayerManager
#include "basic/BasicLayersImpl.h" // for GetEffectiveOperator
#include "CanvasRenderer.h"
#include "CopyableCanvasRenderer.h"
#include "mozilla/mozalloc.h" // for operator new
#include "mozilla/Maybe.h"
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
#include "gfx2DGlue.h"
@ -30,19 +30,33 @@ namespace layers {
void BasicCanvasLayer::Paint(DrawTarget* aDT, const Point& aDeviceOffset,
Layer* aMaskLayer) {
if (IsHidden()) return;
// Ignore IsDirty().
const auto& cr = mCanvasRenderer;
MOZ_ASSERT(cr);
const auto snapshot = cr->BorrowSnapshot();
if (!snapshot) return;
const auto& surface = snapshot->mSurf;
RefPtr<SourceSurface> surface;
CopyableCanvasRenderer* canvasRenderer =
mCanvasRenderer->AsCopyableCanvasRenderer();
MOZ_ASSERT(canvasRenderer);
if (IsDirty()) {
Painted();
Maybe<Matrix> oldTM;
if (!cr->YIsDown()) {
// y-flip
oldTM = Some(aDT->GetTransform());
aDT->SetTransform(Matrix(*oldTM)
surface = canvasRenderer->ReadbackSurface();
}
bool bufferPoviderSnapshot = false;
PersistentBufferProvider* bufferProvider =
canvasRenderer->GetBufferProvider();
if (!surface && bufferProvider) {
surface = bufferProvider->BorrowSnapshot();
bufferPoviderSnapshot = !!surface;
}
if (!surface) {
return;
}
Matrix oldTM;
if (canvasRenderer->NeedsYFlip()) {
oldTM = aDT->GetTransform();
aDT->SetTransform(Matrix(oldTM)
.PreTranslate(0.0f, mBounds.Height())
.PreScale(1.0f, -1.0f));
}
@ -53,15 +67,17 @@ void BasicCanvasLayer::Paint(DrawTarget* aDT, const Point& aDeviceOffset,
DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
aMaskLayer);
if (oldTM) {
aDT->SetTransform(*oldTM);
if (canvasRenderer->NeedsYFlip()) {
aDT->SetTransform(oldTM);
}
Painted();
if (bufferPoviderSnapshot) {
bufferProvider->ReturnSnapshot(surface.forget());
}
}
RefPtr<CanvasRenderer> BasicCanvasLayer::CreateCanvasRendererInternal() {
return new CanvasRenderer();
CanvasRenderer* BasicCanvasLayer::CreateCanvasRendererInternal() {
return new CopyableCanvasRenderer();
}
already_AddRefed<CanvasLayer> BasicLayerManager::CreateCanvasLayer() {

Просмотреть файл

@ -35,7 +35,7 @@ class BasicCanvasLayer : public CanvasLayer, public BasicImplData {
return static_cast<BasicLayerManager*>(mManager);
}
RefPtr<CanvasRenderer> CreateCanvasRendererInternal() override;
CanvasRenderer* CreateCanvasRendererInternal() override;
};
} // namespace layers

Просмотреть файл

@ -7,11 +7,16 @@
#include "CanvasClient.h"
#include "ClientCanvasLayer.h" // for ClientCanvasLayer
#include "GLContext.h" // for GLContext
#include "GLScreenBuffer.h" // for GLScreenBuffer
#include "ScopedGLHelpers.h"
#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
#include "gfxPlatform.h" // for gfxPlatform
#include "GLReadTexImageHelper.h"
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/BufferTexture.h"
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
#include "mozilla/layers/LayersTypes.h"
@ -20,7 +25,9 @@
#include "mozilla/layers/TextureClientOGL.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "nsDebug.h" // for printf_stderr, NS_ASSERTION
#include "nsICanvasRenderingContextInternal.h"
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
#include "TextureClientSharedSurface.h"
using namespace mozilla::gfx;
using namespace mozilla::gl;
@ -28,27 +35,52 @@ using namespace mozilla::gl;
namespace mozilla {
namespace layers {
void CanvasClient::UseTexture(TextureClient* const aTexture) {
/* static */
already_AddRefed<CanvasClient> CanvasClient::CreateCanvasClient(
CanvasClientType aType, CompositableForwarder* aForwarder,
TextureFlags aFlags) {
switch (aType) {
case CanvasClientTypeShSurf:
return MakeAndAddRef<CanvasClientSharedSurface>(aForwarder, aFlags);
case CanvasClientAsync:
return MakeAndAddRef<CanvasClientBridge>(aForwarder, aFlags);
case CanvasClientTypeOOP:
return MakeAndAddRef<CanvasClientOOP>(aForwarder, aFlags);
default:
return MakeAndAddRef<CanvasClient2D>(aForwarder, aFlags);
break;
}
}
void CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer) {
if (!GetForwarder() || !mLayer || !aRenderer ||
!aRenderer->GetCanvasClient()) {
return;
}
CompositableHandle asyncID = aRenderer->GetCanvasClientAsyncHandle();
if (!asyncID || mAsyncHandle == asyncID) {
return;
}
static_cast<ShadowLayerForwarder*>(GetForwarder())
->AttachAsyncCompositable(asyncID, mLayer);
mAsyncHandle = asyncID;
}
void CanvasClient2D::UpdateFromTexture(TextureClient* aTexture) {
MOZ_ASSERT(aTexture);
const auto isClientNonPremult =
bool(mTextureFlags & TextureFlags::NON_PREMULTIPLIED);
const auto isTextureNonPremult =
bool(aTexture->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
MOZ_ALWAYS_TRUE(isTextureNonPremult == isClientNonPremult);
bool changed = false;
if (aTexture != mFrontBuffer) {
if (!aTexture->IsSharedWithCompositor()) {
if (!AddTextureClient(aTexture)) {
return;
}
if (!aTexture->IsSharedWithCompositor()) {
if (!AddTextureClient(aTexture)) {
return;
}
changed = true;
mFrontBuffer = aTexture;
}
mBackBuffer = nullptr;
mFrontBuffer = nullptr;
mBufferProviderTexture = aTexture;
AutoTArray<CompositableForwarder::TimedTextureClient, 1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = aTexture;
@ -56,41 +88,488 @@ void CanvasClient::UseTexture(TextureClient* const aTexture) {
t->mFrameID = mFrameID;
GetForwarder()->UseTextures(this, textures);
if (changed) {
aTexture->SyncWithObject(GetForwarder()->GetSyncObject());
}
aTexture->SyncWithObject(GetForwarder()->GetSyncObject());
}
static constexpr bool kIsWindows =
#ifdef XP_WIN
true;
#else
false;
#endif
void CanvasClient2D::Update(gfx::IntSize aSize,
ShareableCanvasRenderer* aCanvasRenderer) {
mBufferProviderTexture = nullptr;
RefPtr<TextureClient> CanvasClient::CreateTextureClientForCanvas(
const gfx::SurfaceFormat aFormat, const gfx::IntSize aSize,
const TextureFlags aFlags) {
if (kIsWindows) {
// With WebRender, host side uses data of TextureClient longer.
// Then back buffer reuse in CanvasClient2D::Update() does not work. It
// causes a lot of TextureClient allocations. For reducing the allocations,
// TextureClientRecycler is used.
if (GetForwarder() && GetForwarder()->GetCompositorBackendType() ==
LayersBackend::LAYERS_WR) {
return GetTextureClientRecycler()->CreateOrRecycle(
aFormat, aSize, BackendSelector::Canvas, aFlags);
}
return CreateTextureClientForDrawing(aFormat, aSize,
BackendSelector::Canvas, aFlags);
AutoRemoveTexture autoRemove(this);
if (mBackBuffer &&
(mBackBuffer->IsReadLocked() || mBackBuffer->GetSize() != aSize)) {
autoRemove.mTexture = mBackBuffer;
mBackBuffer = nullptr;
}
bool bufferCreated = false;
if (!mBackBuffer) {
gfxContentType contentType = aCanvasRenderer->IsOpaque()
? gfxContentType::COLOR
: gfxContentType::COLOR_ALPHA;
gfx::SurfaceFormat surfaceFormat =
gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType);
TextureFlags flags = TextureFlags::DEFAULT;
if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
}
flags |= TextureFlags::NON_BLOCKING_READ_LOCK;
mBackBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags,
aCanvasRenderer);
if (!mBackBuffer) {
NS_WARNING("Failed to allocate the TextureClient");
return;
}
MOZ_ASSERT(mBackBuffer->CanExposeDrawTarget());
bufferCreated = true;
}
bool updated = false;
{
TextureClientAutoLock autoLock(mBackBuffer, OpenMode::OPEN_WRITE_ONLY);
if (!autoLock.Succeeded()) {
mBackBuffer = nullptr;
return;
}
RefPtr<DrawTarget> target = mBackBuffer->BorrowDrawTarget();
if (target) {
if (!aCanvasRenderer->UpdateTarget(target)) {
NS_WARNING("Failed to copy the canvas into a TextureClient.");
return;
}
updated = true;
}
}
if (bufferCreated && !AddTextureClient(mBackBuffer)) {
mBackBuffer = nullptr;
return;
}
if (updated) {
AutoTArray<CompositableForwarder::TimedTextureClient, 1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = mBackBuffer;
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBackBuffer->GetSize());
t->mFrameID = mFrameID;
GetForwarder()->UseTextures(this, textures);
mBackBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
}
mBackBuffer.swap(mFrontBuffer);
}
already_AddRefed<TextureClient> CanvasClient2D::CreateTextureClientForCanvas(
gfx::SurfaceFormat aFormat, gfx::IntSize aSize, TextureFlags aFlags,
ShareableCanvasRenderer* aCanvasRenderer) {
if (aCanvasRenderer->HasGLContext()) {
// We want a cairo backend here as we don't want to be copying into
// an accelerated backend and we like LockBits to work. This is currently
// the most effective way to make this work.
return TextureClient::CreateForRawBufferAccess(GetForwarder(), aFormat,
aSize, BackendType::CAIRO,
mTextureFlags | aFlags);
}
#ifdef XP_WIN
// With WebRender, host side uses data of TextureClient longer.
// Then back buffer reuse in CanvasClient2D::Update() does not work. It causes
// a lot of TextureClient allocations.
// For reducing the allocations, TextureClientRecycler is used.
if (GetForwarder() &&
GetForwarder()->GetCompositorBackendType() == LayersBackend::LAYERS_WR) {
return GetTextureClientRecycler()->CreateOrRecycle(
aFormat, aSize, BackendSelector::Canvas, aFlags);
}
return CreateTextureClientForDrawing(aFormat, aSize, BackendSelector::Canvas,
aFlags);
#else
// XXX - We should use CreateTextureClientForDrawing, but we first need
// to use double buffering.
gfx::BackendType backend =
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
return TextureClient::CreateForRawBufferAccess(
GetForwarder(), aFormat, aSize, backend, mTextureFlags | aFlags);
#endif
}
////////////////////////////////////////////////////////////////////////
CanvasClientSharedSurface::CanvasClientSharedSurface(
CompositableForwarder* aLayerForwarder, TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags) {}
CanvasClientSharedSurface::~CanvasClientSharedSurface() { ClearSurfaces(); }
////////////////////////////////////////
// Readback
// For formats compatible with R8G8B8A8.
static inline void SwapRB_R8G8B8A8(uint8_t* pixel) {
// [RR, GG, BB, AA]
std::swap(pixel[0], pixel[2]);
}
class TexClientFactory {
CompositableForwarder* const mAllocator;
const bool mHasAlpha;
const gfx::IntSize mSize;
const gfx::BackendType mBackendType;
const TextureFlags mBaseTexFlags;
const LayersBackend mLayersBackend;
public:
TexClientFactory(CompositableForwarder* allocator, bool hasAlpha,
const gfx::IntSize& size, gfx::BackendType backendType,
TextureFlags baseTexFlags, LayersBackend layersBackend)
: mAllocator(allocator),
mHasAlpha(hasAlpha),
mSize(size),
mBackendType(backendType),
mBaseTexFlags(baseTexFlags),
mLayersBackend(layersBackend) {}
protected:
already_AddRefed<TextureClient> Create(gfx::SurfaceFormat format) {
return TextureClient::CreateForRawBufferAccess(mAllocator, format, mSize,
mBackendType, mBaseTexFlags);
}
public:
already_AddRefed<TextureClient> CreateB8G8R8AX8() {
gfx::SurfaceFormat format =
mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8 : gfx::SurfaceFormat::B8G8R8X8;
return Create(format);
}
already_AddRefed<TextureClient> CreateR8G8B8AX8() {
RefPtr<TextureClient> ret;
bool areRGBAFormatsBroken = mLayersBackend == LayersBackend::LAYERS_BASIC;
if (!areRGBAFormatsBroken) {
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
: gfx::SurfaceFormat::R8G8B8X8;
if (gfxVars::UseWebRender() && format == gfx::SurfaceFormat::R8G8B8X8) {
MOZ_CRASH("R8G8B8X8 is not supported on WebRender");
}
ret = Create(format);
}
if (!ret) {
ret = CreateB8G8R8AX8();
if (ret) {
ret->AddFlags(TextureFlags::RB_SWAPPED);
}
}
return ret.forget();
}
};
static already_AddRefed<TextureClient> TexClientFromReadback(
SharedSurface* src, CompositableForwarder* allocator,
TextureFlags baseFlags, LayersBackend layersBackend) {
auto backendType = gfx::BackendType::SKIA;
TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType,
baseFlags, layersBackend);
RefPtr<TextureClient> texClient;
{
gl::ScopedReadbackFB autoReadback(src);
// We have a source FB, now we need a format.
GLenum destFormat = LOCAL_GL_BGRA;
GLenum destType = LOCAL_GL_UNSIGNED_BYTE;
GLenum readFormat;
GLenum readType;
// We actually don't care if they match, since we can handle
// any read{Format,Type} we get.
auto gl = src->mGL;
GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType);
MOZ_ASSERT(readFormat == LOCAL_GL_RGBA || readFormat == LOCAL_GL_BGRA);
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
// With a format and type, we can create texClient.
if (readFormat == LOCAL_GL_BGRA && readType == LOCAL_GL_UNSIGNED_BYTE) {
// 0xAARRGGBB
// In Lendian: [BB, GG, RR, AA]
texClient = factory.CreateB8G8R8AX8();
} else if (readFormat == LOCAL_GL_RGBA &&
readType == LOCAL_GL_UNSIGNED_BYTE) {
// [RR, GG, BB, AA]
texClient = factory.CreateR8G8B8AX8();
} else {
MOZ_CRASH("GFX: Bad `read{Format,Type}`.");
}
if (!texClient) {
gfxWarning() << "Couldn't create texClient for readback.";
return nullptr;
}
// With a texClient, we can lock for writing.
TextureClientAutoLock autoLock(texClient, OpenMode::OPEN_WRITE);
DebugOnly<bool> succeeded = autoLock.Succeeded();
MOZ_ASSERT(succeeded, "texture should have locked");
MappedTextureData mapped;
texClient->BorrowMappedData(mapped);
// ReadPixels from the current FB into mapped.data.
auto width = src->mSize.width;
auto height = src->mSize.height;
auto stride = mapped.stride;
{
ScopedPackState scopedPackState(gl);
bool handled = scopedPackState.SetForWidthAndStrideRGBA(width, stride);
MOZ_RELEASE_ASSERT(handled, "Unhandled stride");
gl->raw_fReadPixels(0, 0, width, height, readFormat, readType,
mapped.data);
}
// RB_SWAPPED doesn't work with D3D11. (bug 1051010)
// RB_SWAPPED doesn't work with Basic. (bug ???????)
bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC ||
layersBackend == LayersBackend::LAYERS_D3D11;
if (texClient->HasFlags(TextureFlags::RB_SWAPPED) &&
layersNeedsManualSwap) {
size_t pixels = width * height;
uint8_t* itr = mapped.data;
for (size_t i = 0; i < pixels; i++) {
SwapRB_R8G8B8A8(itr);
itr += 4;
}
texClient->RemoveFlags(TextureFlags::RB_SWAPPED);
}
}
return texClient.forget();
}
////////////////////////////////////////
static already_AddRefed<SharedSurfaceTextureClient> CloneSurface(
gl::SharedSurface* src, gl::SurfaceFactory* factory) {
RefPtr<SharedSurfaceTextureClient> dest = factory->NewTexClient(src->mSize);
if (!dest) {
return nullptr;
}
gl::SharedSurface* destSurf = dest->Surf();
destSurf->ProducerAcquire();
bool ret = SharedSurface::ProdCopy(src, dest->Surf(), factory);
destSurf->ProducerRelease();
if (!ret) {
return nullptr;
}
return dest.forget();
}
void CanvasClientSharedSurface::Update(
gfx::IntSize aSize, ShareableCanvasRenderer* aCanvasRenderer) {
Renderer renderer;
renderer.construct<ShareableCanvasRenderer*>(aCanvasRenderer);
UpdateRenderer(aSize, renderer);
}
void CanvasClientSharedSurface::UpdateAsync(AsyncCanvasRenderer* aRenderer) {
Renderer renderer;
renderer.construct<AsyncCanvasRenderer*>(aRenderer);
UpdateRenderer(aRenderer->GetSize(), renderer);
}
void CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize,
Renderer& aRenderer) {
GLContext* gl = nullptr;
ShareableCanvasRenderer* canvasRenderer = nullptr;
AsyncCanvasRenderer* asyncRenderer = nullptr;
if (aRenderer.constructed<ShareableCanvasRenderer*>()) {
canvasRenderer = aRenderer.ref<ShareableCanvasRenderer*>();
gl = canvasRenderer->mGLContext;
} else {
asyncRenderer = aRenderer.ref<AsyncCanvasRenderer*>();
gl = asyncRenderer->mGLContext;
}
if (!gl->MakeCurrent()) return;
RefPtr<TextureClient> newFront;
mShSurfClient = nullptr;
if (gl->Screen()) {
mShSurfClient = gl->Screen()->Front();
if (mShSurfClient && mShSurfClient->GetAllocator() &&
mShSurfClient->GetAllocator() !=
GetForwarder()->GetTextureForwarder()) {
mShSurfClient =
CloneSurface(mShSurfClient->Surf(), gl->Screen()->Factory().get());
}
}
if (!mShSurfClient) {
gfxCriticalError() << "Invalid canvas front buffer or screen";
return;
}
newFront = mShSurfClient;
SharedSurface* surf = mShSurfClient->Surf();
if (!surf->IsBufferAvailable()) {
// SharedSurface is already forwared to compositor side.
// SharedSurface::Commit() could not be called again.
// It happens only with SharedSurface_SurfaceTexture.
if (!mNewFront && !mFront) {
// This could happen when CanvasClientSharedSurface is re-created, but
// GLScreenBuffer is not re-created.
// See Bug 1626142
mNewFront = newFront;
} else {
NS_WARNING("SharedSurface buffer not available, skip update");
}
return;
}
// Readback if needed.
mReadbackClient = nullptr;
auto forwarder = GetForwarder();
bool needsReadback = (surf->mType == SharedSurfaceType::Basic);
if (needsReadback) {
TextureFlags flags = TextureFlags::IMMUTABLE;
CompositableForwarder* shadowForwarder = nullptr;
if (canvasRenderer) {
flags |= canvasRenderer->Flags();
shadowForwarder = canvasRenderer->GetForwarder();
} else {
MOZ_ASSERT(asyncRenderer);
flags |= mTextureFlags;
shadowForwarder = GetForwarder();
}
auto layersBackend = shadowForwarder->GetCompositorBackendType();
mReadbackClient =
TexClientFromReadback(surf, forwarder, flags, layersBackend);
newFront = mReadbackClient;
} else {
mReadbackClient = nullptr;
}
surf->Commit();
if (asyncRenderer) {
// If surface type is Basic, above codes will readback
// the GLContext to mReadbackClient in order to send frame to
// compositor. We copy from this TextureClient directly by
// calling CopyFromTextureClient().
// Therefore, if main-thread want the content of GLContext,
// it doesn't have to readback from GLContext again.
//
// Otherwise, if surface type isn't Basic, we will read from
// SharedSurface directly from main-thread. We still pass
// mReadbackClient which is nullptr here to tell
// AsyncCanvasRenderer reset some properties.
asyncRenderer->CopyFromTextureClient(mReadbackClient);
}
if (!newFront) {
// May happen in a release build in case of memory pressure.
gfxWarning()
<< "Failed to allocate a TextureClient for SharedSurface Canvas. Size: "
<< aSize;
return;
}
mNewFront = newFront;
}
void CanvasClientSharedSurface::Updated() {
if (!mNewFront) {
return;
}
auto forwarder = GetForwarder();
mFront = mNewFront;
mNewFront = nullptr;
// Add the new TexClient.
if (!AddTextureClient(mFront)) {
return;
}
AutoTArray<CompositableForwarder::TimedTextureClient, 1> textures;
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
t->mTextureClient = mFront;
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize());
t->mFrameID = mFrameID;
forwarder->UseTextures(this, textures);
}
void CanvasClientSharedSurface::OnDetach() { ClearSurfaces(); }
void CanvasClientSharedSurface::ClearSurfaces() {
mFront = nullptr;
mNewFront = nullptr;
mShSurfClient = nullptr;
mReadbackClient = nullptr;
}
//----------------------------------------------------------------------------
CanvasClientOOP::CanvasClientOOP(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags) {}
CanvasClientOOP::~CanvasClientOOP() = default;
void CanvasClientOOP::SetLayer(ShadowableLayer* aLayer,
OOPCanvasRenderer* aRenderer) {
mLayer = aLayer;
mCanvasContext = aRenderer->mContext;
MOZ_ASSERT(mCanvasContext);
Connect();
aRenderer->mCanvasClient = this;
}
void CanvasClientOOP::Update(gfx::IntSize aSize,
ShareableCanvasRenderer* aRenderer) {
if (!GetForwarder() || !mLayer || !mCanvasContext || !aRenderer) {
return;
}
// Make sure the host is using the right Compositable.
CompositableHandle handle = GetIPCHandle();
if (!handle || mHandle == handle) {
return;
}
MOZ_ASSERT(GetForwarder() && GetForwarder()->AsLayerForwarder() &&
GetForwarder()->AsLayerForwarder()->GetShadowManager());
static_cast<ShadowLayerForwarder*>(GetForwarder())->Attach(this, mLayer);
LayerTransactionChild* ltc =
GetForwarder()->AsLayerForwarder()->GetShadowManager();
bool success = mCanvasContext->UpdateCompositableHandle(ltc, handle);
if (!success) {
return;
}
mHandle = handle;
}
} // namespace layers

Просмотреть файл

@ -23,46 +23,196 @@
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Types.h" // for SurfaceFormat
class nsICanvasRenderingContextInternal;
namespace mozilla {
namespace layers {
class AsyncCanvasRenderer;
class ShareableCanvasRenderer;
class CompositableForwarder;
class ShadowableLayer;
class SharedSurfaceTextureClient;
class OOPCanvasRenderer;
/**
* Compositable client for 2d and webgl canvas.
*/
class CanvasClient final : public CompositableClient {
int32_t mFrameID = 0;
RefPtr<TextureClient> mFrontBuffer;
class CanvasClient : public CompositableClient {
public:
typedef MaybeOneOf<ShareableCanvasRenderer*, AsyncCanvasRenderer*> Renderer;
/**
* Creates, configures, and returns a new canvas client. If necessary, a
* message will be sent to the compositor to create a corresponding image
* host.
*/
CanvasClient(CompositableForwarder* aFwd, const TextureFlags flags)
: CompositableClient(aFwd, flags) {}
enum CanvasClientType {
CanvasClientSurface,
CanvasClientGLContext,
CanvasClientTypeShSurf,
CanvasClientAsync, // webgl on workers
CanvasClientTypeOOP, // webgl in remote process
};
static already_AddRefed<CanvasClient> CreateCanvasClient(
CanvasClientType aType, CompositableForwarder* aFwd, TextureFlags aFlags);
CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags)
: CompositableClient(aFwd, aFlags), mFrameID(0) {
mTextureFlags = aFlags;
}
virtual ~CanvasClient() = default;
void Clear() { mFrontBuffer = nullptr; }
virtual void Clear(){};
virtual void Update(gfx::IntSize aSize,
ShareableCanvasRenderer* aCanvasRenderer) = 0;
bool AddTextureClient(TextureClient* aTexture) override {
++mFrameID;
return CompositableClient::AddTextureClient(aTexture);
}
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {}
virtual void UpdateFromTexture(TextureClient* aTexture) {}
virtual void Updated() {}
protected:
int32_t mFrameID;
};
// Used for 2D canvases and WebGL canvas on non-GL systems where readback is
// requried.
class CanvasClient2D : public CanvasClient {
public:
CanvasClient2D(CompositableForwarder* aLayerForwarder, TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags) {}
TextureInfo GetTextureInfo() const override {
return TextureInfo(CompositableType::IMAGE, mTextureFlags);
}
void OnDetach() override { Clear(); }
void Clear() override {
mBackBuffer = mFrontBuffer = mBufferProviderTexture = nullptr;
}
RefPtr<TextureClient> CreateTextureClientForCanvas(gfx::SurfaceFormat,
gfx::IntSize,
TextureFlags);
void UseTexture(TextureClient*);
void Update(gfx::IntSize aSize,
ShareableCanvasRenderer* aCanvasRenderer) override;
void UpdateFromTexture(TextureClient* aBuffer) override;
bool AddTextureClient(TextureClient* aTexture) override {
return CanvasClient::AddTextureClient(aTexture);
}
void OnDetach() override { mBackBuffer = mFrontBuffer = nullptr; }
private:
already_AddRefed<TextureClient> CreateTextureClientForCanvas(
gfx::SurfaceFormat aFormat, gfx::IntSize aSize, TextureFlags aFlags,
ShareableCanvasRenderer* aCanvasRenderer);
RefPtr<TextureClient> mBackBuffer;
RefPtr<TextureClient> mFrontBuffer;
// We store this texture separately to make sure it is not written into
// in Update() if for some silly reason we end up alternating between
// UpdateFromTexture and Update.
// This code is begging for a cleanup. The situation described above should
// not be made possible.
RefPtr<TextureClient> mBufferProviderTexture;
};
// Used for GL canvases where we don't need to do any readback, i.e., with a
// GL backend.
class CanvasClientSharedSurface : public CanvasClient {
private:
RefPtr<SharedSurfaceTextureClient> mShSurfClient;
RefPtr<TextureClient> mReadbackClient;
RefPtr<TextureClient> mFront;
RefPtr<TextureClient> mNewFront;
void ClearSurfaces();
public:
CanvasClientSharedSurface(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags);
~CanvasClientSharedSurface();
TextureInfo GetTextureInfo() const override {
return TextureInfo(CompositableType::IMAGE);
}
void Clear() override { ClearSurfaces(); }
void Update(gfx::IntSize aSize,
ShareableCanvasRenderer* aCanvasRenderer) override;
void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer);
void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
void Updated() override;
void OnDetach() override;
};
/**
* Used for OMT<canvas> uploads using the image bridge protocol.
* Actual CanvasClient is on the ImageBridgeChild thread, so we
* only forward its AsyncID here
*/
class CanvasClientBridge final : public CanvasClient {
public:
CanvasClientBridge(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags), mLayer(nullptr) {
mIsAsync = true;
}
TextureInfo GetTextureInfo() const override {
return TextureInfo(CompositableType::IMAGE);
}
void Update(gfx::IntSize aSize,
ShareableCanvasRenderer* aCanvasRenderer) override {}
void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
void SetLayer(ShadowableLayer* aLayer) { mLayer = aLayer; }
protected:
CompositableHandle mAsyncHandle;
ShadowableLayer* mLayer;
};
/**
* Used for WebGL instances that perform all composition in the host process.
*/
class CanvasClientOOP final : public CanvasClient {
public:
CanvasClientOOP(CompositableForwarder* aLayerForwarder, TextureFlags aFlags);
~CanvasClientOOP();
TextureInfo GetTextureInfo() const override {
return TextureInfo(CompositableType::IMAGE);
}
virtual void Update(gfx::IntSize aSize,
ShareableCanvasRenderer* aCanvasRenderer) override;
virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override {
MOZ_ASSERT_UNREACHABLE("Illegal to call UpdateAsync on CanvasClientOOP");
}
void SetLayer(ShadowableLayer* aLayer, OOPCanvasRenderer* aRenderer);
protected:
nsICanvasRenderingContextInternal* mCanvasContext = nullptr;
ShadowableLayer* mLayer = nullptr;
CompositableHandle mHandle;
};
} // namespace layers

Просмотреть файл

@ -26,7 +26,7 @@ void ClientCanvasLayer::RenderLayer() {
ClientManager()->Hold(this);
}
RefPtr<CanvasRenderer> ClientCanvasLayer::CreateCanvasRendererInternal() {
CanvasRenderer* ClientCanvasLayer::CreateCanvasRendererInternal() {
return new ClientCanvasRenderer(this);
}

Просмотреть файл

@ -30,7 +30,7 @@ class ClientCanvasLayer : public CanvasLayer, public ClientLayer {
MOZ_COUNT_CTOR(ClientCanvasLayer);
}
RefPtr<CanvasRenderer> CreateCanvasRendererInternal() override;
CanvasRenderer* CreateCanvasRendererInternal() override;
protected:
virtual ~ClientCanvasLayer();
@ -59,7 +59,7 @@ class ClientCanvasLayer : public CanvasLayer, public ClientLayer {
Layer* AsLayer() override { return this; }
ShadowableLayer* AsShadowableLayer() override { return this; }
void Disconnect() override { mCanvasRenderer->DisconnectClient(); }
void Disconnect() override { mCanvasRenderer->Destroy(); }
CompositableClient* GetCompositableClient() override {
ClientCanvasRenderer* canvasRenderer =

Просмотреть файл

@ -17,16 +17,35 @@ CompositableForwarder* ClientCanvasRenderer::GetForwarder() {
bool ClientCanvasRenderer::CreateCompositable() {
if (!mCanvasClient) {
auto compositableFlags = TextureFlags::NO_FLAGS;
if (!mData.mIsAlphaPremult) {
// WR needs this flag marked on the compositable, not just the texture.
compositableFlags |= TextureFlags::NON_PREMULTIPLIED;
TextureFlags flags = TextureFlags::DEFAULT;
if (mOriginPos == gl::OriginPos::BottomLeft) {
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
}
if (IsOpaque()) {
flags |= TextureFlags::IS_OPAQUE;
}
if (!mIsAlphaPremultiplied) {
flags |= TextureFlags::NON_PREMULTIPLIED;
}
mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
GetForwarder(), flags);
if (!mCanvasClient) {
return false;
}
mCanvasClient = new CanvasClient(GetForwarder(), compositableFlags);
if (mLayer->HasShadow()) {
mCanvasClient->Connect();
GetForwarder()->AsLayerForwarder()->Attach(mCanvasClient, mLayer);
if (mAsyncRenderer) {
static_cast<CanvasClientBridge*>(mCanvasClient.get())->SetLayer(mLayer);
} else if (mOOPRenderer) {
static_cast<CanvasClientOOP*>(mCanvasClient.get())
->SetLayer(mLayer, mOOPRenderer);
} else {
mCanvasClient->Connect();
GetForwarder()->AsLayerForwarder()->Attach(mCanvasClient, mLayer);
}
}
}

Просмотреть файл

@ -13,8 +13,7 @@ namespace mozilla {
namespace layers {
class ClientCanvasLayer;
class ClientCanvasRenderer final : public ShareableCanvasRenderer {
class ClientCanvasRenderer : public ShareableCanvasRenderer {
public:
explicit ClientCanvasRenderer(ClientCanvasLayer* aLayer) : mLayer(aLayer) {}

Просмотреть файл

@ -324,15 +324,6 @@ static TextureType GetTextureType(gfx::SurfaceFormat aFormat,
return TextureType::Unknown;
}
TextureType PreferredCanvasTextureType(
const KnowsCompositor& aKnowsCompositor) {
const auto layersBackend = aKnowsCompositor.GetCompositorBackendType();
const auto moz2DBackend =
BackendTypeForBackendSelector(layersBackend, BackendSelector::Canvas);
return GetTextureType(gfx::SurfaceFormat::R8G8B8A8, {1, 1}, layersBackend,
moz2DBackend, 2, TextureAllocationFlags::ALLOC_DEFAULT);
}
static bool ShouldRemoteTextureType(TextureType aTextureType,
BackendSelector aSelector) {
if (!XRE_IsContentProcess()) {

Просмотреть файл

@ -335,7 +335,7 @@ class TextureData {
* lifetime. This means that the lifetime of the underlying shared data
* matches the lifetime of the TextureClient/Host pair. It also means
* TextureClient/Host do not implement double buffering, which is the
* responsibility of the compositable (which would use pairs of Textures).
* responsibility of the compositable (which would use two Texture pairs).
* In order to send several different buffers to the compositor side, use
* several TextureClients.
*/
@ -907,8 +907,6 @@ class TKeepAlive : public KeepAlive {
bool UpdateYCbCrTextureClient(TextureClient* aTexture,
const PlanarYCbCrData& aData);
TextureType PreferredCanvasTextureType(const KnowsCompositor&);
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -20,17 +20,16 @@ namespace mozilla {
namespace layers {
SharedSurfaceTextureData::SharedSurfaceTextureData(
const SurfaceDescriptor& desc, const gfx::SurfaceFormat format,
const gfx::IntSize size)
: mDesc(desc), mFormat(format), mSize(size) {}
UniquePtr<gl::SharedSurface> surf)
: mSurf(std::move(surf)) {}
SharedSurfaceTextureData::~SharedSurfaceTextureData() = default;
void SharedSurfaceTextureData::Deallocate(LayersIPCChannel*) {}
void SharedSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const {
aInfo.size = mSize;
aInfo.format = mFormat;
aInfo.size = mSurf->mSize;
aInfo.format = gfx::SurfaceFormat::UNKNOWN;
aInfo.hasIntermediateBuffer = false;
aInfo.hasSynchronization = false;
aInfo.supportsMoz2D = false;
@ -38,22 +37,26 @@ void SharedSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const {
}
bool SharedSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
aOutDescriptor = mDesc;
return true;
}
/*
static TextureFlags FlagsFrom(const SharedSurfaceDescriptor& desc) {
auto flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
if (!desc.isPremultAlpha) {
flags |= TextureFlags::NON_PREMULTIPLIED;
}
return flags;
return mSurf->ToSurfaceDescriptor(&aOutDescriptor);
}
SharedSurfaceTextureClient::SharedSurfaceTextureClient(
const SharedSurfaceDescriptor& aDesc, LayersIPCChannel* aAllocator)
: TextureClient(new SharedSurfaceTextureData(desc), FlagsFrom(desc),
aAllocator) { mWorkaroundAnnoyingSharedSurfaceLifetimeIssues = true;
SharedSurfaceTextureData* aData, TextureFlags aFlags,
LayersIPCChannel* aAllocator)
: TextureClient(aData, aFlags, aAllocator) {
mWorkaroundAnnoyingSharedSurfaceLifetimeIssues = true;
}
already_AddRefed<SharedSurfaceTextureClient> SharedSurfaceTextureClient::Create(
UniquePtr<gl::SharedSurface> surf, gl::SurfaceFactory* factory,
LayersIPCChannel* aAllocator, TextureFlags aFlags) {
if (!surf) {
return nullptr;
}
TextureFlags flags = aFlags | TextureFlags::RECYCLE | surf->GetTextureFlags();
SharedSurfaceTextureData* data =
new SharedSurfaceTextureData(std::move(surf));
return MakeAndAddRef<SharedSurfaceTextureClient>(data, flags, aAllocator);
}
SharedSurfaceTextureClient::~SharedSurfaceTextureClient() {
@ -77,7 +80,6 @@ SharedSurfaceTextureClient::~SharedSurfaceTextureClient() {
delete data;
}
}
*/
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -30,15 +30,14 @@ namespace layers {
class SharedSurfaceTextureClient;
class SharedSurfaceTextureData : public TextureData {
protected:
const UniquePtr<gl::SharedSurface> mSurf;
friend class SharedSurfaceTextureClient;
public:
const SurfaceDescriptor mDesc;
const gfx::SurfaceFormat mFormat;
const gfx::IntSize mSize;
explicit SharedSurfaceTextureData(UniquePtr<gl::SharedSurface> surf);
SharedSurfaceTextureData(const SurfaceDescriptor&, gfx::SurfaceFormat,
gfx::IntSize);
public:
virtual ~SharedSurfaceTextureData();
bool Lock(OpenMode) override { return false; }
@ -50,8 +49,10 @@ class SharedSurfaceTextureData : public TextureData {
bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
void Deallocate(LayersIPCChannel*) override;
gl::SharedSurface* Surf() const { return mSurf.get(); }
};
/*
class SharedSurfaceTextureClient : public TextureClient {
public:
SharedSurfaceTextureClient(SharedSurfaceTextureData* aData,
@ -59,16 +60,16 @@ class SharedSurfaceTextureClient : public TextureClient {
~SharedSurfaceTextureClient();
static RefPtr<SharedSurfaceTextureClient> Create(
static already_AddRefed<SharedSurfaceTextureClient> Create(
UniquePtr<gl::SharedSurface> surf, gl::SurfaceFactory* factory,
LayersIPCChannel* aAllocator, TextureFlags aFlags);
const auto& Desc() const {
gl::SharedSurface* Surf() const {
return static_cast<const SharedSurfaceTextureData*>(GetInternalData())
->mDesc;
->Surf();
}
};
*/
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -52,7 +52,7 @@ class CanvasLayerComposite : public CanvasLayer, public LayerComposite {
const char* Name() const override { return "CanvasLayerComposite"; }
protected:
RefPtr<CanvasRenderer> CreateCanvasRendererInternal() override {
CanvasRenderer* CreateCanvasRendererInternal() override {
MOZ_CRASH("Incompatible surface type");
return nullptr;
}

Просмотреть файл

@ -21,6 +21,7 @@
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
@ -232,6 +233,14 @@ void ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
*result = CreateImageClientNow(aType, aImageContainer);
}
// dispatched function
void ImageBridgeChild::CreateCanvasClientSync(
SynchronousTask* aTask, CanvasClient::CanvasClientType aType,
TextureFlags aFlags, RefPtr<CanvasClient>* const outResult) {
AutoCompleteTask complete(aTask);
*outResult = CreateCanvasClientNow(aType, aFlags);
}
ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace)
: mNamespace(aNamespace),
mCanSend(false),
@ -324,6 +333,45 @@ void ImageBridgeChild::UpdateImageClient(RefPtr<ImageContainer> aContainer) {
EndTransaction();
}
void ImageBridgeChild::UpdateAsyncCanvasRendererSync(
SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper) {
AutoCompleteTask complete(aTask);
UpdateAsyncCanvasRendererNow(aWrapper);
}
void ImageBridgeChild::UpdateAsyncCanvasRenderer(
AsyncCanvasRenderer* aWrapper) {
aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
if (InImageBridgeChildThread()) {
UpdateAsyncCanvasRendererNow(aWrapper);
return;
}
SynchronousTask task("UpdateAsyncCanvasRenderer Lock");
RefPtr<Runnable> runnable = WrapRunnable(
RefPtr<ImageBridgeChild>(this),
&ImageBridgeChild::UpdateAsyncCanvasRendererSync, &task, aWrapper);
GetThread()->Dispatch(runnable.forget());
task.Wait();
}
void ImageBridgeChild::UpdateAsyncCanvasRendererNow(
AsyncCanvasRenderer* aWrapper) {
MOZ_ASSERT(aWrapper);
if (!CanSend()) {
return;
}
BeginTransaction();
aWrapper->GetCanvasClient()->Updated();
EndTransaction();
}
void ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
ImageClient* aClient,
ImageContainer* aContainer) {
@ -670,6 +718,37 @@ RefPtr<ImageClient> ImageBridgeChild::CreateImageClientNow(
return client;
}
already_AddRefed<CanvasClient> ImageBridgeChild::CreateCanvasClient(
CanvasClient::CanvasClientType aType, TextureFlags aFlag) {
if (InImageBridgeChildThread()) {
return CreateCanvasClientNow(aType, aFlag);
}
SynchronousTask task("CreateCanvasClient Lock");
// RefPtrs on arguments are not needed since this dispatches synchronously.
RefPtr<CanvasClient> result = nullptr;
RefPtr<Runnable> runnable = WrapRunnable(
RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::CreateCanvasClientSync,
&task, aType, aFlag, &result);
GetThread()->Dispatch(runnable.forget());
task.Wait();
return result.forget();
}
already_AddRefed<CanvasClient> ImageBridgeChild::CreateCanvasClientNow(
CanvasClient::CanvasClientType aType, TextureFlags aFlag) {
RefPtr<CanvasClient> client =
CanvasClient::CreateCanvasClient(aType, this, aFlag);
MOZ_ASSERT(client, "failed to create CanvasClient");
if (client) {
client->Connect();
}
return client.forget();
}
bool ImageBridgeChild::AllocUnsafeShmem(
size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aShmem) {

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/CanvasClient.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/PImageBridgeChild.h"
@ -31,6 +32,7 @@ class Shmem;
namespace layers {
class AsyncCanvasRenderer;
class ImageClient;
class ImageContainer;
class ImageContainerListener;
@ -191,6 +193,9 @@ class ImageBridgeChild final : public PImageBridgeChild,
RefPtr<ImageClient> CreateImageClientNow(CompositableType aType,
ImageContainer* aImageContainer);
already_AddRefed<CanvasClient> CreateCanvasClient(
CanvasClient::CanvasClientType aType, TextureFlags aFlag);
void UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aClient);
void UpdateImageClient(RefPtr<ImageContainer> aContainer);
/**
@ -208,11 +213,22 @@ class ImageBridgeChild final : public PImageBridgeChild,
virtual ~ImageBridgeChild();
// Helpers for dispatching.
already_AddRefed<CanvasClient> CreateCanvasClientNow(
CanvasClient::CanvasClientType aType, TextureFlags aFlags);
void CreateCanvasClientSync(SynchronousTask* aTask,
CanvasClient::CanvasClientType aType,
TextureFlags aFlags,
RefPtr<CanvasClient>* const outResult);
void CreateImageClientSync(SynchronousTask* aTask,
RefPtr<ImageClient>* result,
CompositableType aType,
ImageContainer* aImageContainer);
void UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aClient);
void UpdateAsyncCanvasRendererSync(SynchronousTask* aTask,
AsyncCanvasRenderer* aWrapper);
void FlushAllImagesSync(SynchronousTask* aTask, ImageClient* aClient,
ImageContainer* aContainer);

Просмотреть файл

@ -6,7 +6,6 @@
#include "mozilla/layers/RemoteContentController.h"
#include "CompositorThread.h"
#include "MainThreadUtils.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/layers/APZCCallbackHelper.h"

Просмотреть файл

@ -42,7 +42,7 @@ class CanvasLayerMLGPU final : public CanvasLayer, public TexturedLayerMLGPU {
MOZ_LAYER_DECL_NAME("CanvasLayerMLGPU", TYPE_CANVAS)
protected:
RefPtr<CanvasRenderer> CreateCanvasRendererInternal() override {
CanvasRenderer* CreateCanvasRendererInternal() override {
MOZ_CRASH("Incompatible surface type");
return nullptr;
}

Просмотреть файл

@ -122,6 +122,7 @@ EXPORTS.mozilla.layers += [
'apz/util/ScrollLinkedEffectDetector.h',
'apz/util/TouchActionHelper.h',
'apz/util/TouchCounter.h',
'AsyncCanvasRenderer.h',
'AtomicRefCountedWithFinalize.h',
'AxisPhysicsModel.h',
'AxisPhysicsMSDModel.h',
@ -166,6 +167,7 @@ EXPORTS.mozilla.layers += [
'CompositionRecorder.h',
'Compositor.h',
'CompositorTypes.h',
'CopyableCanvasRenderer.h',
'D3D11ShareHandleImage.h',
'D3D11YCbCrImage.h',
'D3D9SurfaceImage.h',
@ -379,6 +381,7 @@ UNIFIED_SOURCES += [
'apz/util/ScrollLinkedEffectDetector.cpp',
'apz/util/TouchActionHelper.cpp',
'apz/util/TouchCounter.cpp',
'AsyncCanvasRenderer.cpp',
'AxisPhysicsModel.cpp',
'AxisPhysicsMSDModel.cpp',
'basic/BasicCanvasLayer.cpp',
@ -434,6 +437,7 @@ UNIFIED_SOURCES += [
'composite/TiledContentHost.cpp',
'CompositionRecorder.cpp',
'Compositor.cpp',
'CopyableCanvasRenderer.cpp',
'Effects.cpp',
'FrameMetrics.cpp',
'GLImages.cpp',
@ -588,7 +592,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
LOCAL_INCLUDES += [
'/docshell/base', # for nsDocShell.h
'/dom/canvas', # for intertwined WebGL headers
'/layout/base', # for TouchManager.h
'/layout/generic', # for nsTextFrame.h
'/media/libyuv/libyuv/include', # for libyuv.h

Просмотреть файл

@ -242,9 +242,13 @@ already_AddRefed<mozilla::gl::GLContext> CompositorOGL::CreateContext() {
// Allow to create offscreen GL context for main Layer Manager
if (!context && gfxEnv::LayersPreferOffscreen()) {
SurfaceCaps caps = SurfaceCaps::ForRGB();
caps.preserve = false;
caps.bpp16 = gfxVars::OffscreenFormat() == SurfaceFormat::R5G6B5_UINT16;
nsCString discardFailureId;
context = GLContextProvider::CreateOffscreen(
mSurfaceSize, {CreateContextFlags::REQUIRE_COMPAT_PROFILE},
mSurfaceSize, caps, CreateContextFlags::REQUIRE_COMPAT_PROFILE,
&discardFailureId);
}

Просмотреть файл

@ -20,14 +20,14 @@ CompositableForwarder* WebRenderCanvasRenderer::GetForwarder() {
return mManager->WrBridge();
}
WebRenderCanvasRendererAsync::~WebRenderCanvasRendererAsync() {
if (mPipelineId.isSome()) {
mManager->RemovePipelineIdForCompositable(mPipelineId.ref());
mPipelineId.reset();
}
void WebRenderCanvasRenderer::Initialize(const CanvasInitializeData& aData) {
ShareableCanvasRenderer::Initialize(aData);
}
void WebRenderCanvasRendererAsync::Initialize(const CanvasRendererData& aData) {
WebRenderCanvasRendererAsync::~WebRenderCanvasRendererAsync() { Destroy(); }
void WebRenderCanvasRendererAsync::Initialize(
const CanvasInitializeData& aData) {
WebRenderCanvasRenderer::Initialize(aData);
ClearCachedResources();
@ -35,12 +35,25 @@ void WebRenderCanvasRendererAsync::Initialize(const CanvasRendererData& aData) {
bool WebRenderCanvasRendererAsync::CreateCompositable() {
if (!mCanvasClient) {
auto compositableFlags = TextureFlags::NO_FLAGS;
if (!mData.mIsAlphaPremult) {
// WR needs this flag marked on the compositable, not just the texture.
compositableFlags |= TextureFlags::NON_PREMULTIPLIED;
TextureFlags flags = TextureFlags::DEFAULT;
if (mOriginPos == gl::OriginPos::BottomLeft) {
flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
}
mCanvasClient = new CanvasClient(GetForwarder(), compositableFlags);
if (IsOpaque()) {
flags |= TextureFlags::IS_OPAQUE;
}
if (!mIsAlphaPremultiplied) {
flags |= TextureFlags::NON_PREMULTIPLIED;
}
mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
GetForwarder(), flags);
if (!mCanvasClient) {
return false;
}
mCanvasClient->Connect();
}
@ -62,6 +75,13 @@ void WebRenderCanvasRendererAsync::ClearCachedResources() {
}
}
void WebRenderCanvasRendererAsync::Destroy() {
if (mPipelineId.isSome()) {
mManager->RemovePipelineIdForCompositable(mPipelineId.ref());
mPipelineId.reset();
}
}
void WebRenderCanvasRendererAsync::
UpdateCompositableClientForEmptyTransaction() {
bool wasDirty = IsDirty();

Просмотреть файл

@ -19,13 +19,15 @@ class WebRenderCanvasRenderer : public ShareableCanvasRenderer {
explicit WebRenderCanvasRenderer(RenderRootStateManager* aManager)
: mManager(aManager) {}
void Initialize(const CanvasInitializeData& aData) override;
CompositableForwarder* GetForwarder() override;
protected:
RenderRootStateManager* mManager;
};
class WebRenderCanvasRendererAsync final : public WebRenderCanvasRenderer {
class WebRenderCanvasRendererAsync : public WebRenderCanvasRenderer {
public:
explicit WebRenderCanvasRendererAsync(RenderRootStateManager* aManager)
: WebRenderCanvasRenderer(aManager) {}
@ -35,10 +37,11 @@ class WebRenderCanvasRendererAsync final : public WebRenderCanvasRenderer {
return this;
}
void Initialize(const CanvasRendererData& aData) override;
void Initialize(const CanvasInitializeData& aData) override;
bool CreateCompositable() override;
void ClearCachedResources() override;
void Destroy() override;
void UpdateCompositableClientForEmptyTransaction();

Просмотреть файл

@ -370,7 +370,7 @@ WebRenderCanvasRendererAsync* WebRenderCanvasData::GetCanvasRenderer() {
}
WebRenderCanvasRendererAsync* WebRenderCanvasData::CreateCanvasRenderer() {
mCanvasRenderer = new WebRenderCanvasRendererAsync(mManager);
mCanvasRenderer = MakeUnique<WebRenderCanvasRendererAsync>(mManager);
return mCanvasRenderer.get();
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше