Bug 1541472 - Remove Advanced Layers, since it's disabled everywhere now. r=jrmuizel

Differential Revision: https://phabricator.services.mozilla.com/D104592
This commit is contained in:
Matt Woodrow 2021-02-10 02:04:41 +00:00
parent 31e436ffe0
commit f9e8884de8
70 changed files with 32 additions and 11294 deletions

View File

@ -198,7 +198,6 @@ mozilla::ipc::IPCResult RDDParent::RecvInitVideoBridge(
Feature::HW_COMPOSITING,
Feature::D3D11_COMPOSITING,
Feature::OPENGL_COMPOSITING,
Feature::ADVANCED_LAYERS,
Feature::DIRECT2D,
Feature::WEBGPU,
},

View File

@ -167,9 +167,6 @@ void gfxConfig::Inherit(EnumSet<Feature> aFeatures,
case Feature::OPENGL_COMPOSITING:
status = aDevicePrefs.oglCompositing();
break;
case Feature::ADVANCED_LAYERS:
status = aDevicePrefs.advancedLayers();
break;
case Feature::DIRECT2D:
status = aDevicePrefs.useD2D1();
break;

View File

@ -33,7 +33,6 @@ namespace gfx {
_(WEBRENDER_DCOMP_PRESENT, Feature, "WebRender DirectComposition") \
_(WEBRENDER_SOFTWARE, Feature, "WebRender software fallback") \
_(OMTP, Feature, "Off Main Thread Painting") \
_(ADVANCED_LAYERS, Feature, "Advanced Layers") \
_(WEBGPU, Feature, "WebGPU") \
/* Add new entries above this comment */

View File

@ -1,372 +0,0 @@
Advanced Layers
===============
Note: Advanced Layers has been deprecated in favor of WebRender.
Advanced Layers is a new method of compositing layers in Gecko. This
document serves as a technical overview and provides a short
walk-through of its source code.
Overview
--------
Advanced Layers attempts to group as many GPU operations as it can into
a single draw call. This is a common technique in GPU-based rendering
called “batching”. It is not always trivial, as a batching algorithm can
easily waste precious CPU resources trying to build optimal draw calls.
Advanced Layers reuses the existing Gecko layers system as much as
possible. Huge layer trees do not currently scale well (see the future
work section), so opportunities for batching are currently limited
without expending unnecessary resources elsewhere. However, Advanced
Layers has a few benefits:
- It submits smaller GPU workloads and buffer uploads than the existing
compositor.
- It needs only a single pass over the layer tree.
- It uses occlusion information more intelligently.
- It is easier to add new specialized rendering paths and new layer
types.
- It separates compositing logic from device logic, unlike the existing
compositor.
- It is much faster at rendering 3d scenes or complex layer trees.
- It has experimental code to use the z-buffer for occlusion culling.
Because of these benefits we hope that it provides a significant
improvement over the existing compositor.
Advanced Layers uses the acronym “MLG” and “MLGPU” in many places. This
stands for “Mid-Level Graphics”, the idea being that it is optimized for
Direct3D 11-style rendering systems as opposed to Direct3D 12 or Vulkan.
LayerManagerMLGPU
-----------------
Advanced layers does not change client-side rendering at all. Content
still uses Direct2D (when possible), and creates identical layer trees
as it would with a normal Direct3D 11 compositor. In fact, Advanced
Layers re-uses all of the existing texture handling and video
infrastructure as well, replacing only the composite-side layer types.
Advanced Layers does not create a ``LayerManagerComposite`` - instead,
it creates a ``LayerManagerMLGPU``. This layer manager does not have a
``Compositor`` - instead, it has an ``MLGDevice``, which roughly
abstracts the Direct3D 11 API. (The hope is that this API is easily
interchangeable for something else when cross-platform or software
support is needed.)
``LayerManagerMLGPU`` also dispenses with the old “composite” layers for
new layer types. For example, ``ColorLayerComposite`` becomes
``ColorLayerMLGPU``. Since these layer types implement ``HostLayer``,
they integrate with ``LayerTransactionParent`` as normal composite
layers would.
Rendering Overview
------------------
The steps for rendering are described in more detail below, but roughly
the process is:
1. Sort layers front-to-back.
2. Create a dependency tree of render targets (called “views”).
3. Accumulate draw calls for all layers in each view.
4. Upload draw call buffers to the GPU.
5. Execute draw commands for each view.
Advanced Layers divides the layer tree into “views”
(``RenderViewMLGPU``), which correspond to a render target. The root
layer is represented by a view corresponding to the screen. Layers that
require intermediate surfaces have temporary views. Layers are analyzed
front-to-back, and rendered back-to-front within a view. Views
themselves are rendered front-to-back, to minimize render target
switching.
Each view contains one or more rendering passes (``RenderPassMLGPU``). A
pass represents a single draw command with one or more rendering items
attached to it. For example, a ``SolidColorPass`` item contains a
rectangle and an RGBA value, and many of these can be drawn with a
single GPU call.
When considering a layer, views will first try to find an existing
rendering batch that can support it. If so, that pass will accumulate
another draw item for the layer. Otherwise, a new pass will be added.
When trying to find a matching pass for a layer, there is a tradeoff in
CPU time versus the GPU time saved by not issuing another draw commands.
We generally care more about CPU time, so we do not try too hard in
matching items to an existing batch.
After all layers have been processed, there is a “prepare” step. This
copies all accumulated draw data and uploads it into vertex and constant
buffers in the GPU.
Finally, we execute rendering commands. At the end of the frame, all
batches and (most) constant buffers are thrown away.
Shaders Overview
----------------
Advanced Layers currently has five layer-related shader pipelines:
- Textured (PaintedLayer, ImageLayer, CanvasLayer)
- ComponentAlpha (PaintedLayer with component-alpha)
- YCbCr (ImageLayer with YCbCr video)
- Color (ColorLayers)
- Blend (ContainerLayers with mix-blend modes)
There are also three special shader pipelines:
- MaskCombiner, which is used to combine mask layers into a single
texture.
- Clear, which is used for fast region-based clears when not directly
supported by the GPU.
- Diagnostic, which is used to display the diagnostic overlay texture.
The layer shaders follow a unified structure. Each pipeline has a vertex
and pixel shader. The vertex shader takes a layers ID, a z-buffer depth,
a unit position in either a unit square or unit triangle, and either
rectangular or triangular geometry. Shaders can also have ancillary data
needed like texture coordinates or colors.
Most of the time, layers have simple rectangular clips with simple
rectilinear transforms, and pixel shaders do not need to perform masking
or clipping. For these layers we use a fast-path pipeline, using
unit-quad shaders that are able to clip geometry so the pixel shader
does not have to. This type of pipeline does not support complex masks.
If a layer has a complex mask, a rotation or 3d transform, or a complex
operation like blending, then we use shaders capable of handling
arbitrary geometry. Their input is a unit triangle, and these shaders
are generally more expensive.
All of the shader-specific data is modelled in ShaderDefinitionsMLGPU.h.
CPU Occlusion Culling
---------------------
By default, Advanced Layers performs occlusion culling on the CPU. Since
layers are visited front-to-back, this is simply a matter of
accumulating the visible region of opaque layers, and subtracting it
from the visible region of subsequent layers. There is a major
difference between this occlusion culling and PostProcessLayers of the
old compositor: AL performs culling after invalidation, not before.
Completely valid layers will have an empty visible region.
Most layer types (with the exception of images) will intelligently split
their draw calls into a batch of individual rectangles, based on their
visible region.
Z-Buffering and Occlusion
-------------------------
Advanced Layers also supports occlusion culling on the GPU, using a
z-buffer. This is disabled by default currently since it is
significantly costly on integrated GPUs. When using the z-buffer, we
separate opaque layers into a separate list of passes. The render
process then uses the following steps:
1. The depth buffer is set to read-write.
2. Opaque batches are executed.,
3. The depth buffer is set to read-only.
4. Transparent batches are executed.
The problem we have observed is that the depth buffer increases writes
to the GPU, and on integrated GPUs this is expensive - we have seen draw
call times increase by 20-30%, which is the wrong direction we want to
take on battery life. In particular on a full screen video, the call to
ClearDepthStencilView plus the actual depth buffer write of the video
can double GPU time.
For now the depth-buffer is disabled until we can find a compelling case
for it on non-integrated hardware.
Clipping
--------
Clipping is a bit tricky in Advanced Layers. We cannot use the hardware
“scissor” feature, since the clip can change from instance to instance
within a batch. And if using the depth buffer, we cannot write
transparent pixels for the clipped area. As a result we always clip
opaque draw rects in the vertex shader (and sometimes even on the CPU,
as is needed for sane texture coordinates). Only transparent items are
clipped in the pixel shader. As a result, masked layers and layers with
non-rectangular transforms are always considered transparent, and use a
more flexible clipping pipeline.
Plane Splitting
---------------
Plane splitting is when a 3D transform causes a layer to be split - for
example, one transparent layer may intersect another on a separate
plane. When this happens, Gecko sorts layers using a BSP tree and
produces a list of triangles instead of draw rects.
These layers cannot use the “unit quad” shaders that support the fast
clipping pipeline. Instead they always use the full triangle-list
shaders that support extended vertices and clipping.
This is the slowest path we can take when building a draw call, since we
must interact with the polygon clipping and texturing code.
Masks
-----
For each layer with a mask attached, Advanced Layers builds a
``MaskOperation``. These operations must resolve to a single mask
texture, as well as a rectangular area to which the mask applies. All
batched pixel shaders will automatically clip pixels to the mask if a
mask texture is bound. (Note that we must use separate batches if the
mask texture changes.)
Some layers have multiple mask textures. In this case, the MaskOperation
will store the list of masks, and right before rendering, it will invoke
a shader to combine these masks into a single texture.
MaskOperations are shared across layers when possible, but are not
cached across frames.
BigImage Support
----------------
ImageLayers and CanvasLayers can be tiled with many individual textures.
This happens in rare cases where the underlying buffer is too big for
the GPU. Early on this caused problems for Advanced Layers, since AL
required one texture per layer. We implemented BigImage support by
creating temporary ImageLayers for each visible tile, and throwing those
layers away at the end of the frame.
Advanced Layers no longer has a 1:1 layer:texture restriction, but we
retain the temporary layer solution anyway. It is not much code and it
means we do not have to split ``TexturedLayerMLGPU`` methods into
iterated and non-iterated versions.
Texture Locking
---------------
Advanced Layers has a different texture locking scheme than the existing
compositor. If a texture needs to be locked, then it is locked by the
MLGDevice automatically when bound to the current pipeline. The
MLGDevice keeps a set of the locked textures to avoid double-locking. At
the end of the frame, any textures in the locked set are unlocked.
We cannot easily replicate the locking scheme in the old compositor,
since the duration of using the texture is not scoped to when we visit
the layer.
Buffer Measurements
-------------------
Advanced Layers uses constant buffers to send layer information and
extended instance data to the GPU. We do this by pre-allocating large
constant buffers and mapping them with ``MAP_DISCARD`` at the beginning
of the frame. Batches may allocate into this up to the maximum bindable
constant buffer size of the device (currently, 64KB).
There are some downsides to this approach. Constant buffers are
difficult to work with - they have specific alignment requirements, and
care must be taken not too run over the maximum number of constants in a
buffer. Another approach would be to store constants in a 2D texture and
use vertex shader texture fetches. Advanced Layers implemented this and
benchmarked it to decide which approach to use. Textures seemed to skew
better on GPU performance, but worse on CPU, but this varied depending
on the GPU. Overall constant buffers performed best and most
consistently, so we have kept them.
Additionally, we tested different ways of performing buffer uploads.
Buffer creation itself is costly, especially on integrated GPUs, and
especially so for immutable, immediate-upload buffers. As a result we
aggressively cache buffer objects and always allocate them as
MAP_DISCARD unless they are write-once and long-lived.
Buffer Types
------------
Advanced Layers has a few different classes to help build and upload
buffers to the GPU. They are:
- ``MLGBuffer``. This is the low-level shader resource that
``MLGDevice`` exposes. It is the building block for buffer helper
classes, but it can also be used to make one-off, immutable,
immediate-upload buffers. MLGBuffers, being a GPU resource, are
reference counted.
- ``SharedBufferMLGPU``. These are large, pre-allocated buffers that
are read-only on the GPU and write-only on the CPU. They usually
exceed the maximum bindable buffer size. There are three shared
buffers created by default and they are automatically unmapped as
needed: one for vertices, one for vertex shader constants, and one
for pixel shader constants. When callers allocate into a shared
buffer they get back a mapped pointer, a GPU resource, and an offset.
When the underlying device supports offsetable buffers (like
``ID3D11DeviceContext1`` does), this results in better GPU
utilization, as there are less resources and fewer upload commands.
- ``ConstantBufferSection`` and ``VertexBufferSection``. These are
“views” into a ``SharedBufferMLGPU``. They contain the underlying
``MLGBuffer``, and when offsetting is supported, the offset
information necessary for resource binding. Sections are not
reference counted.
- ``StagingBuffer``. A dynamically sized CPU buffer where items can be
appended in a free-form manner. The stride of a single “item” is
computed by the first item written, and successive items must have
the same stride. The buffer must be uploaded to the GPU manually.
Staging buffers are appropriate for creating general constant or
vertex buffer data. They can also write items in reverse, which is
how we render back-to-front when layers are visited front-to-back.
They can be uploaded to a ``SharedBufferMLGPU`` or an immutabler
``MLGBuffer`` very easily. Staging buffers are not reference counted.
Unsupported Features
--------------------
Currently, these features of the old compositor are not yet implemented.
- OpenGL and software support (currently AL only works on D3D11).
- APZ displayport overlay.
- Diagnostic/developer overlays other than the FPS/timing overlay.
- DEAA. It was never ported to the D3D11 compositor, but we would like
it.
- Component alpha when used inside an opaque intermediate surface.
- Effects prefs. Possibly not needed post-B2G removal.
- Widget overlays and underlays used by macOS and Android.
- DefaultClearColor. This is Android specific, but is easy to added
when needed.
- Frame uniformity info in the profiler. Possibly not needed post-B2G
removal.
- LayerScope. There are no plans to make this work.
Future Work
-----------
- Refactor for D3D12/Vulkan support (namely, split MLGDevice into
something less stateful and something else more low-level).
- Remove “MLG” moniker and namespace everything.
- Other backends (D3D12/Vulkan, OpenGL, Software)
- Delete CompositorD3D11
- Add DEAA support
- Re-enable the depth buffer by default for fast GPUs
- Re-enable right-sizing of inaccurately sized containers
- Drop constant buffers for ancillary vertex data
- Fast shader paths for simple video/painted layer cases
History
-------
Advanced Layers has gone through four major design iterations. The
initial version used tiling - each render view divided the screen into
128x128 tiles, and layers were assigned to tiles based on their
screen-space draw area. This approach proved not to scale well to 3d
transforms, and so tiling was eliminated.
We replaced it with a simple system of accumulating draw regions to each
batch, thus ensuring that items could be assigned to batches while
maintaining correct z-ordering. This second iteration also coincided
with plane-splitting support.
On large layer trees, accumulating the affected regions of batches
proved to be quite expensive. This led to a third iteration, using depth
buffers and separate opaque and transparent batch lists to achieve
z-ordering and occlusion culling.
Finally, depth buffers proved to be too expensive, and we introduced a
simple CPU-based occlusion culling pass. This iteration coincided with
using more precise draw rects and splitting pipelines into unit-quad,
cpu-clipped and triangle-list, gpu-clipped variants.

View File

@ -56,7 +56,6 @@ void GPUChild::Init() {
gfxConfig::GetValue(Feature::D3D11_COMPOSITING);
devicePrefs.oglCompositing() =
gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
devicePrefs.advancedLayers() = gfxConfig::GetValue(Feature::ADVANCED_LAYERS);
devicePrefs.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
devicePrefs.webGPU() = gfxConfig::GetValue(Feature::WEBGPU);
devicePrefs.d3d11HwAngle() = gfxConfig::GetValue(Feature::D3D11_HW_ANGLE);

View File

@ -46,7 +46,6 @@
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/ImageBridgeParent.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "mozilla/layers/MemoryReportingMLGPU.h"
#include "mozilla/layers/UiCompositorControllerParent.h"
#include "mozilla/layers/VideoBridgeParent.h"
#include "mozilla/webrender/RenderThread.h"
@ -136,7 +135,6 @@ bool GPUParent::Init(base::ProcessId aParentPid, const char* aParentBuildID,
gfxPlatform::InitNullMetadata();
// Ensure our Factory is initialised, mainly for gfx logging to work.
gfxPlatform::InitMoz2DLogging();
mlg::InitializeMemoryReporters();
#if defined(XP_WIN)
gfxWindowsPlatform::InitMemoryReportersForGPUProcess();
DeviceManagerDx::Init();
@ -194,7 +192,6 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
gfxConfig::Inherit(Feature::D3D11_COMPOSITING,
devicePrefs.d3d11Compositing());
gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, devicePrefs.oglCompositing());
gfxConfig::Inherit(Feature::ADVANCED_LAYERS, devicePrefs.advancedLayers());
gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1());
gfxConfig::Inherit(Feature::WEBGPU, devicePrefs.webGPU());
gfxConfig::Inherit(Feature::D3D11_HW_ANGLE, devicePrefs.d3d11HwAngle());
@ -426,7 +423,6 @@ static void CopyFeatureChange(Feature aFeature, Maybe<FeatureFailure>* aOut) {
mozilla::ipc::IPCResult GPUParent::RecvGetDeviceStatus(GPUDeviceData* aOut) {
CopyFeatureChange(Feature::D3D11_COMPOSITING, &aOut->d3d11Compositing());
CopyFeatureChange(Feature::OPENGL_COMPOSITING, &aOut->oglCompositing());
CopyFeatureChange(Feature::ADVANCED_LAYERS, &aOut->advancedLayers());
#if defined(XP_WIN)
if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {

View File

@ -32,7 +32,6 @@ struct DevicePrefs
FeatureStatus hwCompositing;
FeatureStatus d3d11Compositing;
FeatureStatus oglCompositing;
FeatureStatus advancedLayers;
FeatureStatus useD2D1;
FeatureStatus webGPU;
FeatureStatus d3d11HwAngle;
@ -59,7 +58,6 @@ struct GPUDeviceData
// null.
FeatureFailure? d3d11Compositing;
FeatureFailure? oglCompositing;
FeatureFailure? advancedLayers;
D3D11DeviceStatus? gpuDevice;
FeatureFailure? webGPU;
};

View File

@ -72,8 +72,6 @@ class TextureSourceProvider;
class CompositingRenderTarget;
struct FPSState;
class PaintCounter;
class LayerMLGPU;
class LayerManagerMLGPU;
class UiCompositorControllerParent;
class Layer;
struct LayerProperties;
@ -126,7 +124,6 @@ class HostLayerManager : public LayerManager {
virtual void InvalidateAll() = 0;
HostLayerManager* AsHostLayerManager() override { return this; }
virtual LayerManagerMLGPU* AsLayerManagerMLGPU() { return nullptr; }
void ExtractImageCompositeNotifications(
nsTArray<ImageCompositeNotificationInfo>* aNotifications) {
@ -551,8 +548,6 @@ class HostLayer {
virtual Layer* GetLayer() = 0;
virtual LayerMLGPU* AsLayerMLGPU() { return nullptr; }
virtual bool SetCompositableHost(CompositableHost*) {
// We must handle this gracefully, see bug 967824
NS_WARNING(

File diff suppressed because it is too large Load Diff

View File

@ -1,326 +0,0 @@
/* -*- 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_gfx_layers_d3d11_MLGDeviceD3D11_h
#define mozilla_gfx_layers_d3d11_MLGDeviceD3D11_h
#include <d3d11_1.h>
#include "mozilla/layers/MLGDevice.h"
#include "mozilla/layers/SyncObject.h"
#include "mozilla/EnumeratedArray.h"
#include "nsTHashtable.h"
#include "nsPrintfCString.h"
namespace mozilla {
namespace layers {
struct GPUStats;
struct ShaderBytes;
class DiagnosticsD3D11;
class MLGRenderTargetD3D11 final : public MLGRenderTarget {
public:
MLGRenderTargetD3D11(const gfx::IntSize& aSize, MLGRenderTargetFlags aFlags);
// Create with a new texture.
bool Initialize(ID3D11Device* aDevice);
// Do not create a texture - use the given one provided, which may be null.
// The depth buffer is still initialized.
bool Initialize(ID3D11Device* aDevice, ID3D11Texture2D* aTexture);
gfx::IntSize GetSize() const override;
MLGRenderTargetD3D11* AsD3D11() override { return this; }
MLGTexture* GetTexture() override;
// This is exposed only for MLGSwapChainD3D11.
bool UpdateTexture(ID3D11Texture2D* aTexture);
ID3D11DepthStencilView* GetDSV();
ID3D11RenderTargetView* GetRenderTargetView();
private:
bool CreateDepthBuffer(ID3D11Device* aDevice);
void ForgetTexture();
private:
virtual ~MLGRenderTargetD3D11();
private:
RefPtr<ID3D11Texture2D> mTexture;
RefPtr<ID3D11RenderTargetView> mRTView;
RefPtr<ID3D11Texture2D> mDepthBuffer;
RefPtr<ID3D11DepthStencilView> mDepthStencilView;
RefPtr<MLGTexture> mTextureSource;
gfx::IntSize mSize;
};
class MLGSwapChainD3D11 final : public MLGSwapChain {
public:
static RefPtr<MLGSwapChainD3D11> Create(MLGDeviceD3D11* aParent,
ID3D11Device* aDevice,
widget::CompositorWidget* aWidget);
RefPtr<MLGRenderTarget> AcquireBackBuffer() override;
gfx::IntSize GetSize() const override;
bool ResizeBuffers(const gfx::IntSize& aSize) override;
void CopyBackbuffer(gfx::DrawTarget* aTarget,
const gfx::IntRect& aBounds) override;
void Present() override;
void ForcePresent() override;
void Destroy() override;
private:
MLGSwapChainD3D11(MLGDeviceD3D11* aParent, ID3D11Device* aDevice);
virtual ~MLGSwapChainD3D11();
bool Initialize(widget::CompositorWidget* aWidget);
void UpdateBackBufferContents(ID3D11Texture2D* aBack);
private:
RefPtr<MLGDeviceD3D11> mParent;
RefPtr<ID3D11Device> mDevice;
RefPtr<IDXGISwapChain> mSwapChain;
RefPtr<IDXGISwapChain1> mSwapChain1;
RefPtr<MLGRenderTargetD3D11> mRT;
widget::CompositorWidget* mWidget;
gfx::IntSize mSize;
bool mCanUsePartialPresents;
};
class MLGResourceD3D11 {
public:
virtual ID3D11Resource* GetResource() const = 0;
};
class MLGBufferD3D11 final : public MLGBuffer, public MLGResourceD3D11 {
public:
static RefPtr<MLGBufferD3D11> Create(ID3D11Device* aDevice,
MLGBufferType aType, uint32_t aSize,
MLGUsage aUsage,
const void* aInitialData);
MLGBufferD3D11* AsD3D11() override { return this; }
ID3D11Resource* GetResource() const override { return mBuffer; }
ID3D11Buffer* GetBuffer() const { return mBuffer; }
MLGResourceD3D11* AsResourceD3D11() override { return this; }
size_t GetSize() const override { return mSize; }
protected:
MLGBufferD3D11(ID3D11Buffer* aBuffer, MLGBufferType aType, size_t aSize);
virtual ~MLGBufferD3D11();
private:
RefPtr<ID3D11Buffer> mBuffer;
MLGBufferType mType;
size_t mSize;
};
class MLGTextureD3D11 final : public MLGTexture, public MLGResourceD3D11 {
public:
explicit MLGTextureD3D11(ID3D11Texture2D* aTexture);
static RefPtr<MLGTextureD3D11> Create(ID3D11Device* aDevice,
const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat,
MLGUsage aUsage,
MLGTextureFlags aFlags);
MLGTextureD3D11* AsD3D11() override { return this; }
MLGResourceD3D11* AsResourceD3D11() override { return this; }
ID3D11Texture2D* GetTexture() const { return mTexture; }
ID3D11Resource* GetResource() const override { return mTexture; }
ID3D11ShaderResourceView* GetShaderResourceView();
private:
RefPtr<ID3D11Texture2D> mTexture;
RefPtr<ID3D11ShaderResourceView> mView;
};
class MLGDeviceD3D11 final : public MLGDevice {
public:
explicit MLGDeviceD3D11(ID3D11Device* aDevice);
virtual ~MLGDeviceD3D11();
bool Initialize() override;
void StartDiagnostics(uint32_t aInvalidPixels) override;
void EndDiagnostics() override;
void GetDiagnostics(GPUStats* aStats) override;
MLGDeviceD3D11* AsD3D11() override { return this; }
TextureFactoryIdentifier GetTextureFactoryIdentifier(
widget::CompositorWidget* aWidget) const override;
RefPtr<MLGSwapChain> CreateSwapChainForWidget(
widget::CompositorWidget* aWidget) override;
int32_t GetMaxTextureSize() const override;
LayersBackend GetLayersBackend() const override;
void EndFrame() override;
bool Map(MLGResource* aResource, MLGMapType aType,
MLGMappedResource* aMap) override;
void Unmap(MLGResource* aResource) override;
void UpdatePartialResource(MLGResource* aResource, const gfx::IntRect* aRect,
void* aData, uint32_t aStride) override;
void CopyTexture(MLGTexture* aDest, const gfx::IntPoint& aTarget,
MLGTexture* aSource, const gfx::IntRect& aRect) override;
RefPtr<DataTextureSource> CreateDataTextureSource(
TextureFlags aFlags) override;
void SetRenderTarget(MLGRenderTarget* aRT) override;
MLGRenderTarget* GetRenderTarget() override;
void SetViewport(const gfx::IntRect& aViewport) override;
void SetScissorRect(const Maybe<gfx::IntRect>& aScissorRect) override;
void SetVertexShader(VertexShaderID aVertexShader) override;
void SetPixelShader(PixelShaderID aPixelShader) override;
void SetSamplerMode(uint32_t aIndex, SamplerMode aSamplerMode) override;
void SetBlendState(MLGBlendState aBlendState) override;
void SetVertexBuffer(uint32_t aSlot, MLGBuffer* aBuffer, uint32_t aStride,
uint32_t aOffset) override;
void SetPSTextures(uint32_t aSlot, uint32_t aNumTextures,
TextureSource* const* aTextures) override;
void SetPSTexture(uint32_t aSlot, MLGTexture* aTexture) override;
void SetPSTexturesNV12(uint32_t aSlot, TextureSource* aTexture) override;
void SetPrimitiveTopology(MLGPrimitiveTopology aTopology) override;
void SetDepthTestMode(MLGDepthTestMode aMode) override;
void SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) override;
void SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) override;
void SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
uint32_t aFirstConstant,
uint32_t aNumConstants) override;
void SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
uint32_t aFirstConstant,
uint32_t aNumConstants) override;
RefPtr<MLGBuffer> CreateBuffer(MLGBufferType aType, uint32_t aSize,
MLGUsage aUsage,
const void* aInitialData) override;
RefPtr<MLGRenderTarget> CreateRenderTarget(
const gfx::IntSize& aSize, MLGRenderTargetFlags aFlags) override;
RefPtr<MLGTexture> CreateTexture(const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat, MLGUsage aUsage,
MLGTextureFlags aFlags) override;
RefPtr<MLGTexture> CreateTexture(TextureSource* aSource) override;
void Clear(MLGRenderTarget* aRT, const gfx::DeviceColor& aColor) override;
void ClearDepthBuffer(MLGRenderTarget* aRT) override;
void ClearView(MLGRenderTarget* aRT, const gfx::DeviceColor& aColor,
const gfx::IntRect* aRects, size_t aNumRects) override;
void Draw(uint32_t aVertexCount, uint32_t aOffset) override;
void DrawInstanced(uint32_t aVertexCountPerInstance, uint32_t aInstanceCount,
uint32_t aVertexOffset, uint32_t aInstanceOffset) override;
void Flush() override;
// This is exposed for TextureSourceProvider.
ID3D11Device* GetD3D11Device() const { return mDevice; }
bool Synchronize() override;
void UnlockAllTextures() override;
void InsertPresentWaitQuery();
void WaitForPreviousPresentQuery();
void HandleDeviceReset(const char* aWhere);
private:
bool InitSyncObject();
void MaybeLockTexture(ID3D11Texture2D* aTexture);
bool InitPixelShader(PixelShaderID aShaderID);
bool InitVertexShader(VertexShaderID aShaderID);
bool InitInputLayout(D3D11_INPUT_ELEMENT_DESC* aDesc, size_t aNumElements,
const ShaderBytes& aCode, VertexShaderID aShaderID);
bool InitRasterizerStates();
bool InitSamplerStates();
bool InitBlendStates();
bool InitDepthStencilState();
bool VerifyConstantBufferOffsetting() override;
void SetInputLayout(ID3D11InputLayout* aLayout);
void SetVertexShader(ID3D11VertexShader* aShader);
// Resolve a TextureSource to an ID3D11ShaderResourceView, locking the
// texture if needed. The lock is released at the end of the frame.
ID3D11ShaderResourceView* ResolveTextureSourceForShader(
TextureSource* aSource);
private:
RefPtr<ID3D11Device> mDevice;
RefPtr<ID3D11DeviceContext> mCtx;
RefPtr<ID3D11DeviceContext1> mCtx1;
UniquePtr<DiagnosticsD3D11> mDiagnostics;
typedef EnumeratedArray<PixelShaderID, PixelShaderID::MaxShaders,
RefPtr<ID3D11PixelShader>>
PixelShaderArray;
typedef EnumeratedArray<VertexShaderID, VertexShaderID::MaxShaders,
RefPtr<ID3D11VertexShader>>
VertexShaderArray;
typedef EnumeratedArray<VertexShaderID, VertexShaderID::MaxShaders,
RefPtr<ID3D11InputLayout>>
InputLayoutArray;
typedef EnumeratedArray<SamplerMode, SamplerMode::MaxModes,
RefPtr<ID3D11SamplerState>>
SamplerStateArray;
typedef EnumeratedArray<MLGBlendState, MLGBlendState::MaxStates,
RefPtr<ID3D11BlendState>>
BlendStateArray;
typedef EnumeratedArray<MLGDepthTestMode, MLGDepthTestMode::MaxModes,
RefPtr<ID3D11DepthStencilState>>
DepthStencilStateArray;
PixelShaderArray mPixelShaders;
VertexShaderArray mVertexShaders;
InputLayoutArray mInputLayouts;
SamplerStateArray mSamplerStates;
BlendStateArray mBlendStates;
DepthStencilStateArray mDepthStencilStates;
RefPtr<ID3D11RasterizerState> mRasterizerStateNoScissor;
RefPtr<ID3D11RasterizerState> mRasterizerStateScissor;
RefPtr<SyncObjectHost> mSyncObject;
RefPtr<MLGBuffer> mUnitQuadVB;
RefPtr<MLGBuffer> mUnitTriangleVB;
RefPtr<ID3D11VertexShader> mCurrentVertexShader;
RefPtr<ID3D11InputLayout> mCurrentInputLayout;
RefPtr<ID3D11PixelShader> mCurrentPixelShader;
RefPtr<ID3D11BlendState> mCurrentBlendState;
RefPtr<ID3D11Query> mWaitForPresentQuery;
RefPtr<ID3D11Query> mNextWaitForPresentQuery;
nsTHashtable<nsRefPtrHashKey<IDXGIKeyedMutex>> mLockedTextures;
nsTHashtable<nsRefPtrHashKey<IDXGIKeyedMutex>> mLockAttemptedTextures;
typedef EnumeratedArray<PixelShaderID, PixelShaderID::MaxShaders,
const ShaderBytes*>
LazyPixelShaderArray;
LazyPixelShaderArray mLazyPixelShaders;
typedef EnumeratedArray<VertexShaderID, VertexShaderID::MaxShaders,
const ShaderBytes*>
LazyVertexShaderArray;
LazyVertexShaderArray mLazyVertexShaders;
bool mScissored;
};
} // namespace layers
} // namespace mozilla
struct ShaderBytes;
#endif // mozilla_gfx_layers_d3d11_MLGDeviceD3D11_h

View File

@ -54,7 +54,6 @@
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/ImageBridgeParent.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayerManagerMLGPU.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/OMTASampler.h"
@ -347,9 +346,7 @@ CompositorBridgeParent::CompositorBridgeParent(
mForceCompositionTask(nullptr),
mCompositorScheduler(nullptr),
mAnimationStorage(nullptr),
mPaintTime(TimeDuration::Forever())
{
}
mPaintTime(TimeDuration::Forever()) {}
void CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget,
const LayersId& aLayerTreeId) {
@ -1369,55 +1366,24 @@ void CompositorBridgeParent::InitializeLayerManager(
NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
NS_ASSERTION(!mCompositor, "Already initialised mCompositor");
if (!InitializeAdvancedLayers(aBackendHints, nullptr)) {
mCompositor = NewCompositor(aBackendHints);
if (!mCompositor) {
return;
}
#ifdef XP_WIN
if (mCompositor->AsBasicCompositor() && XRE_IsGPUProcess()) {
// BasicCompositor does not use CompositorWindow,
// then if CompositorWindow exists, it needs to be destroyed.
mWidget->AsWindows()->DestroyCompositorWindow();
}
#endif
mLayerManager = new LayerManagerComposite(mCompositor);
mCompositor = NewCompositor(aBackendHints);
if (!mCompositor) {
return;
}
#ifdef XP_WIN
if (mCompositor->AsBasicCompositor() && XRE_IsGPUProcess()) {
// BasicCompositor does not use CompositorWindow,
// then if CompositorWindow exists, it needs to be destroyed.
mWidget->AsWindows()->DestroyCompositorWindow();
}
#endif
mLayerManager = new LayerManagerComposite(mCompositor);
mLayerManager->SetCompositorBridgeID(mCompositorBridgeID);
MonitorAutoLock lock(*sIndirectLayerTreesLock);
sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = mLayerManager;
}
bool CompositorBridgeParent::InitializeAdvancedLayers(
const nsTArray<LayersBackend>& aBackendHints,
TextureFactoryIdentifier* aOutIdentifier) {
#ifdef XP_WIN
if (!mOptions.UseAdvancedLayers()) {
return false;
}
// Currently LayerManagerMLGPU hardcodes a D3D11 device, so we reject using
// AL if LAYERS_D3D11 isn't in the backend hints.
if (!aBackendHints.Contains(LayersBackend::LAYERS_D3D11)) {
return false;
}
RefPtr<LayerManagerMLGPU> manager = new LayerManagerMLGPU(mWidget);
if (!manager->Initialize()) {
return false;
}
if (aOutIdentifier) {
*aOutIdentifier = manager->GetTextureFactoryIdentifier();
}
mLayerManager = manager;
return true;
#else
return false;
#endif
}
RefPtr<Compositor> CompositorBridgeParent::NewCompositor(
const nsTArray<LayersBackend>& aBackendHints) {
for (size_t i = 0; i < aBackendHints.Length(); ++i) {

View File

@ -745,8 +745,6 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
void CompositeToTarget(VsyncId aId, gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect = nullptr) override;
bool InitializeAdvancedLayers(const nsTArray<LayersBackend>& aBackendHints,
TextureFactoryIdentifier* aOutIdentifier);
RefPtr<Compositor> NewCompositor(
const nsTArray<LayersBackend>& aBackendHints);

View File

@ -1,96 +0,0 @@
/* -*- 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 "BufferCache.h"
#include "MLGDevice.h"
#include "ShaderDefinitionsMLGPU.h"
#include "mozilla/MathAlgorithms.h"
namespace mozilla {
namespace layers {
using namespace mlg;
BufferCache::BufferCache(MLGDevice* aDevice)
: mDevice(aDevice),
mFirstSizeClass(CeilingLog2(kConstantBufferElementSize)),
mFrameNumber(0),
mNextSizeClassToShrink(0) {
// Create a cache of buffers for each size class, where each size class is a
// power of 2 between the minimum and maximum size of a constant buffer.
size_t maxBindSize = mDevice->GetMaxConstantBufferBindSize();
MOZ_ASSERT(IsPowerOfTwo(maxBindSize));
size_t lastSizeClass = CeilingLog2(maxBindSize);
MOZ_ASSERT(lastSizeClass >= mFirstSizeClass);
mCaches.resize(lastSizeClass - mFirstSizeClass + 1);
}
BufferCache::~BufferCache() = default;
RefPtr<MLGBuffer> BufferCache::GetOrCreateBuffer(size_t aBytes) {
size_t sizeClass = CeilingLog2(aBytes);
size_t sizeClassIndex = sizeClass - mFirstSizeClass;
if (sizeClassIndex >= mCaches.size()) {
return mDevice->CreateBuffer(MLGBufferType::Constant, aBytes,
MLGUsage::Dynamic, nullptr);
}
CachePool& pool = mCaches[sizeClassIndex];
// See if we've cached a buffer that wasn't used in the past 2 frames. A
// buffer used this frame could have already been mapped and written to, and a
// buffer used the previous frame might still be in-use by the GPU. While the
// latter case is okay, it causes aliasing in the driver. Since content is
// double buffered we do not let the compositor get more than 1 frames ahead,
// and a count of 2 frames should ensure the buffer is unused.
if (!pool.empty() && mFrameNumber >= pool.front().mLastUsedFrame + 2) {
RefPtr<MLGBuffer> buffer = pool.front().mBuffer;
pool.pop_front();
pool.push_back(CacheEntry(mFrameNumber, buffer));
MOZ_RELEASE_ASSERT(buffer->GetSize() >= aBytes);
return buffer;
}
// Allocate a new buffer and cache it.
size_t bytes = (size_t(1) << sizeClass);
MOZ_ASSERT(bytes >= aBytes);
RefPtr<MLGBuffer> buffer = mDevice->CreateBuffer(
MLGBufferType::Constant, bytes, MLGUsage::Dynamic, nullptr);
if (!buffer) {
return nullptr;
}
pool.push_back(CacheEntry(mFrameNumber, buffer));
return buffer;
}
void BufferCache::EndFrame() {
// Consider a buffer dead after ~5 seconds assuming 60 fps.
static size_t kMaxUnusedFrameCount = 60 * 5;
// At the end of each frame we pick one size class and see if it has any
// buffers that haven't been used for many frames. If so we clear them.
// The next frame we'll search the next size class. (This is just to spread
// work over more than one frame.)
CachePool& pool = mCaches[mNextSizeClassToShrink];
while (!pool.empty()) {
// Since the deque is sorted oldest-to-newest, front-to-back, we can stop
// searching as soon as a buffer is active.
if (mFrameNumber - pool.front().mLastUsedFrame < kMaxUnusedFrameCount) {
break;
}
pool.pop_front();
}
mNextSizeClassToShrink = (mNextSizeClassToShrink + 1) % mCaches.size();
mFrameNumber++;
}
} // namespace layers
} // namespace mozilla

View File

@ -1,82 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_BufferCache_h
#define mozilla_gfx_layers_mlgpu_BufferCache_h
#include "mozilla/EnumeratedArray.h"
#include "mozilla/RefPtr.h"
#include <deque>
#include <vector>
namespace mozilla {
namespace layers {
class MLGBuffer;
class MLGDevice;
// Cache MLGBuffers based on how long ago they were last used.
class BufferCache final {
public:
explicit BufferCache(MLGDevice* aDevice);
~BufferCache();
// Get a buffer that has at least |aBytes|, or create a new one
// if none can be re-used.
RefPtr<MLGBuffer> GetOrCreateBuffer(size_t aBytes);
// Age out old buffers after a frame has been completed.
void EndFrame();
private:
// Not RefPtr since this would create a cycle.
MLGDevice* mDevice;
// The first size class is Log2(N), where 16 is the minimum size of a
// constant buffer (currently 16 bytes).
size_t mFirstSizeClass;
// Each size class is a power of 2. Each pool of buffers is represented as a
// deque, with the least-recently-used (i.e., oldest) buffers at the front,
// and most-recently-used (i.e., newest) buffers at the back. To re-use a
// buffer it is popped off the front and re-added to the back.
//
// This is not always efficient use of storage: if a single frame allocates
// 300 buffers of the same size, we may keep recycling through all those
// buffers for a long time, as long as at least one gets used per frame.
// But since buffers use tiny amounts of memory, and they are only mapped
// while drawing, it shouldn't be a big deal.
struct CacheEntry {
CacheEntry() : mLastUsedFrame(0) {}
// XXX The copy constructor can be deleted once RefPtr's move constructor is
// declared noexcept, see Bug 1612680.
CacheEntry(const CacheEntry& aEntry) = default;
CacheEntry(CacheEntry&& aEntry) = default;
CacheEntry(size_t aLastUsedFrame, MLGBuffer* aBuffer)
: mLastUsedFrame(aLastUsedFrame), mBuffer(aBuffer) {}
uint64_t mLastUsedFrame;
RefPtr<MLGBuffer> mBuffer;
};
typedef std::deque<CacheEntry> CachePool;
// We track how many frames have occurred to determine the age of cache
// entries.
uint64_t mFrameNumber;
// To avoid doing too much work in one frame, we only shrink one size class
// per frame.
uint64_t mNextSizeClassToShrink;
// There is one pool of buffers for each power of 2 allocation size. The
// maximum buffer size is at most 64KB on Direct3D 11.
std::vector<CachePool> mCaches;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_BufferCache_h

View File

@ -1,81 +0,0 @@
/* -*- 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 "CanvasLayerMLGPU.h"
#include "composite/CompositableHost.h" // for CompositableHost
#include "gfx2DGlue.h" // for ToFilter
#include "gfxEnv.h" // for gfxEnv, etc
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/gfx/Point.h" // for Point
#include "mozilla/gfx/Rect.h" // for Rect
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/Effects.h" // for EffectChain
#include "mozilla/layers/ImageHost.h"
#include "mozilla/mozalloc.h" // for operator delete
#include "nsAString.h"
#include "mozilla/RefPtr.h" // for nsRefPtr
#include "MaskOperation.h"
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsString.h" // for nsAutoCString
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
CanvasLayerMLGPU::CanvasLayerMLGPU(LayerManagerMLGPU* aManager)
: CanvasLayer(aManager, nullptr), TexturedLayerMLGPU(aManager) {}
CanvasLayerMLGPU::~CanvasLayerMLGPU() { CleanupResources(); }
Layer* CanvasLayerMLGPU::GetLayer() { return this; }
gfx::SamplingFilter CanvasLayerMLGPU::GetSamplingFilter() {
gfx::SamplingFilter filter = mSamplingFilter;
#ifdef ANDROID
// Bug 691354
// Using the LINEAR filter we get unexplained artifacts.
// Use NEAREST when no scaling is required.
Matrix matrix;
bool is2D = GetEffectiveTransform().Is2D(&matrix);
if (is2D && !ThebesMatrix(matrix).HasNonTranslationOrFlip()) {
filter = SamplingFilter::POINT;
}
#endif
return filter;
}
void CanvasLayerMLGPU::PrintInfo(std::stringstream& aStream,
const char* aPrefix) {
CanvasLayer::PrintInfo(aStream, aPrefix);
aStream << "\n";
if (mHost && mHost->IsAttached()) {
nsAutoCString pfx(aPrefix);
pfx += " ";
mHost->PrintInfo(aStream, pfx.get());
}
}
void CanvasLayerMLGPU::CleanupResources() {
if (mHost) {
mHost->Detach(this);
}
mTexture = nullptr;
mBigImageTexture = nullptr;
mHost = nullptr;
}
void CanvasLayerMLGPU::Disconnect() { CleanupResources(); }
void CanvasLayerMLGPU::ClearCachedResources() { CleanupResources(); }
void CanvasLayerMLGPU::SetRenderRegion(LayerIntRegion&& aRegion) {
aRegion.AndWith(LayerIntRect::FromUnknownRect(mPictureRect));
LayerMLGPU::SetRenderRegion(std::move(aRegion));
}
} // namespace layers
} // namespace mozilla

View File

@ -1,57 +0,0 @@
/* -*- 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_CanvasLayerMLGPU_H
#define GFX_CanvasLayerMLGPU_H
#include "Layers.h" // for CanvasLayer, etc
#include "TexturedLayerMLGPU.h"
#include "mozilla/Attributes.h" // for override
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/layers/LayerManagerMLGPU.h" // for LayerComposite, etc
#include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
#include "nsRect.h" // for mozilla::gfx::IntRect
#include "nscore.h" // for nsACString
namespace mozilla {
namespace layers {
class CompositableHost;
class ImageHost;
class CanvasLayerMLGPU final : public CanvasLayer, public TexturedLayerMLGPU {
public:
explicit CanvasLayerMLGPU(LayerManagerMLGPU* aManager);
protected:
virtual ~CanvasLayerMLGPU();
public:
Layer* GetLayer() override;
void Disconnect() override;
HostLayer* AsHostLayer() override { return this; }
CanvasLayerMLGPU* AsCanvasLayerMLGPU() override { return this; }
gfx::SamplingFilter GetSamplingFilter() override;
void ClearCachedResources() override;
void SetRenderRegion(LayerIntRegion&& aRegion) override;
MOZ_LAYER_DECL_NAME("CanvasLayerMLGPU", TYPE_CANVAS)
protected:
RefPtr<CanvasRenderer> CreateCanvasRendererInternal() override {
MOZ_CRASH("Incompatible surface type");
return nullptr;
}
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
void CleanupResources();
};
} // namespace layers
} // namespace mozilla
#endif /* GFX_CanvasLayerMLGPU_H */

View File

@ -1,30 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_ClearRegionHelper_h
#define mozilla_gfx_layers_mlgpu_ClearRegionHelper_h
#include "SharedBufferMLGPU.h"
namespace mozilla {
namespace layers {
// This is a helper class for issuing a clear operation based on either
// a shader or an API like ClearView. It also works when the depth
// buffer is enabled.
struct ClearRegionHelper {
// If using ClearView-based clears, we fill mRegions.
nsTArray<gfx::IntRect> mRects;
// If using shader-based clears, we fill these buffers.
VertexBufferSection mInput;
ConstantBufferSection mVSBuffer;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_ClearRegionHelper_h

View File

@ -1,242 +0,0 @@
/* -*- 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 "ContainerLayerMLGPU.h"
#include "mozilla/StaticPrefs_layers.h"
#include "LayerManagerMLGPU.h"
#include "MLGDevice.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/Types.h"
#include "UnitTransforms.h"
#include "UtilityMLGPU.h"
namespace mozilla {
namespace layers {
using namespace gfx;
ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
: ContainerLayer(aManager, nullptr),
LayerMLGPU(aManager),
mInvalidateEntireSurface(false),
mSurfaceCopyNeeded(false),
mView(nullptr) {}
ContainerLayerMLGPU::~ContainerLayerMLGPU() {
while (mFirstChild) {
RemoveChild(mFirstChild);
}
}
bool ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder) {
mView = nullptr;
if (!UseIntermediateSurface()) {
// Set this so we invalidate the entire cached render target (if any)
// if our container uses an intermediate surface again later.
mInvalidateEntireSurface = true;
return true;
}
mChildrenChanged = false;
mTargetOffset = GetIntermediateSurfaceRect().TopLeft().ToUnknownPoint();
mTargetSize = GetIntermediateSurfaceRect().Size().ToUnknownSize();
if (mRenderTarget && mRenderTarget->GetSize() != mTargetSize) {
mRenderTarget = nullptr;
}
// Note that if a surface copy is needed, we always redraw the
// whole surface (on-demand). This is a rare case - the old
// Compositor already does this - and it saves us having to
// do much more complicated invalidation.
bool surfaceCopyNeeded = false;
DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
if (surfaceCopyNeeded != mSurfaceCopyNeeded || surfaceCopyNeeded) {
mInvalidateEntireSurface = true;
}
mSurfaceCopyNeeded = surfaceCopyNeeded;
gfx::IntRect viewport(gfx::IntPoint(0, 0), mTargetSize);
if (!mRenderTarget || !StaticPrefs::layers_mlgpu_enable_invalidation() ||
mInvalidateEntireSurface) {
// Fine-grained invalidation is disabled, invalidate everything.
mInvalidRect = viewport;
} else {
// Clamp the invalid rect to the viewport.
mInvalidRect -= mTargetOffset;
mInvalidRect = mInvalidRect.Intersect(viewport);
}
mInvalidateEntireSurface = false;
return true;
}
static IntRect GetTransformedBounds(Layer* aLayer) {
IntRect bounds = aLayer->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
if (bounds.IsEmpty()) {
return bounds;
}
const Matrix4x4& transform = aLayer->GetEffectiveTransform();
Rect rect =
transform.TransformAndClipBounds(Rect(bounds), Rect::MaxIntRect());
rect.RoundOut();
rect.ToIntRect(&bounds);
return bounds;
}
/* static */
Maybe<IntRect> ContainerLayerMLGPU::FindVisibleBounds(
Layer* aLayer, const Maybe<RenderTargetIntRect>& aClip) {
AL_LOG(" visiting child %p\n", aLayer);
AL_LOG_IF(aClip, " parent clip: %s\n", Stringify(aClip.value()).c_str());
ContainerLayer* container = aLayer->AsContainerLayer();
if (container) {
if (container->UseIntermediateSurface()) {
ContainerLayerMLGPU* c =
container->AsHostLayer()->AsLayerMLGPU()->AsContainerLayerMLGPU();
if (!c) {
gfxCriticalError()
<< "not container: "
<< container->AsHostLayer()->AsLayerMLGPU()->GetType();
}
MOZ_RELEASE_ASSERT(c);
c->ComputeIntermediateSurfaceBounds();
} else {
Maybe<IntRect> accumulated = Some(IntRect());
// Traverse children.
for (Layer* child = container->GetFirstChild(); child;
child = child->GetNextSibling()) {
Maybe<RenderTargetIntRect> clip = aClip;
if (const Maybe<ParentLayerIntRect>& childClip =
child->AsHostLayer()->GetShadowClipRect()) {
RenderTargetIntRect rtChildClip = TransformBy(
ViewAs<ParentLayerToRenderTargetMatrix4x4>(
aLayer->GetEffectiveTransform(),
PixelCastJustification::RenderTargetIsParentLayerForRoot),
childClip.value());
clip = IntersectMaybeRects(clip, Some(rtChildClip));
AL_LOG(" target clip: %s\n", Stringify(rtChildClip).c_str());
AL_LOG_IF(clip, " full clip: %s\n",
Stringify(clip.value()).c_str());
}
Maybe<IntRect> childBounds = FindVisibleBounds(child, clip);
if (!childBounds) {
return Nothing();
}
accumulated = accumulated->SafeUnion(childBounds.value());
if (!accumulated) {
return Nothing();
}
}
return accumulated;
}
}
IntRect bounds = GetTransformedBounds(aLayer);
AL_LOG(" layer bounds: %s\n", Stringify(bounds).c_str());
if (aClip) {
bounds = bounds.Intersect(aClip.value().ToUnknownRect());
AL_LOG(" clipped bounds: %s\n", Stringify(bounds).c_str());
}
return Some(bounds);
}
void ContainerLayerMLGPU::ComputeIntermediateSurfaceBounds() {
Maybe<IntRect> bounds = Some(IntRect());
for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
Maybe<RenderTargetIntRect> clip = ViewAs<RenderTargetPixel>(
child->AsHostLayer()->GetShadowClipRect(),
PixelCastJustification::RenderTargetIsParentLayerForRoot);
Maybe<IntRect> childBounds = FindVisibleBounds(child, clip);
if (!childBounds) {
return;
}
bounds = bounds->SafeUnion(childBounds.value());
if (!bounds) {
return;
}
}
SetShadowVisibleRegion(LayerIntRect::FromUnknownRect(bounds.value()));
}
void ContainerLayerMLGPU::OnLayerManagerChange(LayerManagerMLGPU* aManager) {
ClearCachedResources();
}
RefPtr<MLGRenderTarget> ContainerLayerMLGPU::UpdateRenderTarget(
MLGDevice* aDevice, MLGRenderTargetFlags aFlags) {
if (mRenderTarget) {
return mRenderTarget;
}
mRenderTarget = aDevice->CreateRenderTarget(mTargetSize, aFlags);
if (!mRenderTarget) {
gfxWarning()
<< "Failed to create an intermediate render target for ContainerLayer";
return nullptr;
}
return mRenderTarget;
}
void ContainerLayerMLGPU::SetInvalidCompositeRect(const gfx::IntRect* aRect) {
// For simplicity we only track the bounds of the invalid area, since regions
// are expensive.
//
// Note we add the bounds to the invalid rect from the last frame, since we
// only clear the area that we actually paint. If this overflows we use the
// last render target size, since if that changes we'll invalidate everything
// anyway.
if (aRect) {
if (Maybe<gfx::IntRect> result = mInvalidRect.SafeUnion(*aRect)) {
mInvalidRect = result.value();
} else {
mInvalidateEntireSurface = true;
}
} else {
mInvalidateEntireSurface = true;
}
}
void ContainerLayerMLGPU::ClearCachedResources() { mRenderTarget = nullptr; }
bool ContainerLayerMLGPU::IsContentOpaque() {
if (GetMixBlendMode() != gfx::CompositionOp::OP_OVER) {
// We need to read from what's underneath us, so we consider our content to
// be not opaque.
return false;
}
return LayerMLGPU::IsContentOpaque();
}
const LayerIntRegion& ContainerLayerMLGPU::GetShadowVisibleRegion() {
if (!UseIntermediateSurface()) {
RecomputeShadowVisibleRegionFromChildren();
}
return mShadowVisibleRegion;
}
const LayerIntRegion& RefLayerMLGPU::GetShadowVisibleRegion() {
if (!UseIntermediateSurface()) {
RecomputeShadowVisibleRegionFromChildren();
}
return mShadowVisibleRegion;
}
} // namespace layers
} // namespace mozilla

View File

@ -1,96 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_ContainerLayerMLGPU_h
#define mozilla_gfx_layers_mlgpu_ContainerLayerMLGPU_h
#include "LayerMLGPU.h"
#include "MLGDeviceTypes.h"
namespace mozilla {
namespace layers {
class MLGDevice;
class RenderViewMLGPU;
class ContainerLayerMLGPU final : public ContainerLayer, public LayerMLGPU {
public:
explicit ContainerLayerMLGPU(LayerManagerMLGPU* aManager);
virtual ~ContainerLayerMLGPU();
MOZ_LAYER_DECL_NAME("ContainerLayerMLGPU", TYPE_CONTAINER)
HostLayer* AsHostLayer() override { return this; }
ContainerLayerMLGPU* AsContainerLayerMLGPU() override { return this; }
Layer* GetLayer() override { return this; }
void ComputeEffectiveTransforms(
const gfx::Matrix4x4& aTransformToSurface) override {
DefaultComputeEffectiveTransforms(aTransformToSurface);
}
void SetInvalidCompositeRect(const gfx::IntRect* aRect) override;
void ClearCachedResources() override;
const LayerIntRegion& GetShadowVisibleRegion() override;
RefPtr<MLGRenderTarget> UpdateRenderTarget(MLGDevice* aDevice,
MLGRenderTargetFlags aFlags);
MLGRenderTarget* GetRenderTarget() const { return mRenderTarget; }
gfx::IntPoint GetTargetOffset() const { return mTargetOffset; }
gfx::IntSize GetTargetSize() const { return mTargetSize; }
const gfx::IntRect& GetInvalidRect() const { return mInvalidRect; }
void ClearInvalidRect() { mInvalidRect.SetEmpty(); }
bool IsContentOpaque() override;
bool NeedsSurfaceCopy() const { return mSurfaceCopyNeeded; }
RenderViewMLGPU* GetRenderView() const { return mView; }
void SetRenderView(RenderViewMLGPU* aView) {
MOZ_ASSERT(!mView);
mView = aView;
}
void ComputeIntermediateSurfaceBounds();
// Similar to ContainerLayerComposite, we need to include the pres shell
// resolution, if there is one, in the layer's post-scale.
float GetPostXScale() const override {
return mSimpleAttrs.GetPostXScale() * mPresShellResolution;
}
float GetPostYScale() const override {
return mSimpleAttrs.GetPostYScale() * mPresShellResolution;
}
protected:
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
void OnLayerManagerChange(LayerManagerMLGPU* aManager) override;
private:
static Maybe<gfx::IntRect> FindVisibleBounds(
Layer* aLayer, const Maybe<RenderTargetIntRect>& aClip);
RefPtr<MLGRenderTarget> mRenderTarget;
// We cache these since occlusion culling can change the visible region.
gfx::IntPoint mTargetOffset;
gfx::IntSize mTargetSize;
// The region of the container that needs to be recomposited if visible. We
// store this as a rectangle instead of an nsIntRegion for efficiency. This
// is in layer coordinates.
gfx::IntRect mInvalidRect;
bool mInvalidateEntireSurface;
bool mSurfaceCopyNeeded;
// This is only valid for intermediate surfaces while an instance of
// FrameBuilder is live.
RenderViewMLGPU* mView;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_ContainerLayerMLGPU_h

View File

@ -1,412 +0,0 @@
/* -*- 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 "FrameBuilder.h"
#include "ContainerLayerMLGPU.h"
#include "GeckoProfiler.h" // for profiler_*
#include "LayerMLGPU.h"
#include "LayerManagerMLGPU.h"
#include "MaskOperation.h"
#include "MLGDevice.h" // for MLGSwapChain
#include "RenderPassMLGPU.h"
#include "RenderViewMLGPU.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/Polygon.h"
#include "mozilla/layers/BSPTree.h"
#include "mozilla/layers/LayersHelpers.h"
namespace mozilla {
namespace layers {
using namespace mlg;
FrameBuilder::FrameBuilder(LayerManagerMLGPU* aManager,
MLGSwapChain* aSwapChain)
: mManager(aManager),
mDevice(aManager->GetDevice()),
mSwapChain(aSwapChain) {
// test_bug1124898.html has a root ColorLayer, so we don't assume the root is
// a container.
mRoot = mManager->GetRoot()->AsHostLayer()->AsLayerMLGPU();
}
FrameBuilder::~FrameBuilder() = default;
bool FrameBuilder::Build() {
AUTO_PROFILER_LABEL("FrameBuilder::Build", GRAPHICS);
// AcquireBackBuffer can fail, so we check the result here.
RefPtr<MLGRenderTarget> target = mSwapChain->AcquireBackBuffer();
if (!target) {
return false;
}
// This updates the frame sequence number, so layers can quickly check if
// they've already been prepared.
LayerMLGPU::BeginFrame();
// Note: we don't clip draw calls to the invalid region per se, but instead
// the region bounds. Clipping all draw calls would incur a significant
// CPU cost on large layer trees, and would greatly complicate how draw
// rects are added in RenderPassMLGPU, since we would need to break
// each call into additional items based on the intersection with the
// invalid region.
//
// Instead we scissor to the invalid region bounds. As a result, all items
// affecting the invalid bounds are redrawn, even if not all are in the
// precise region.
const nsIntRegion& region = mSwapChain->GetBackBufferInvalidRegion();
mWidgetRenderView = new RenderViewMLGPU(this, target, region);
// Traverse the layer tree and compute visible region for intermediate
// surfaces
if (ContainerLayerMLGPU* root =
mRoot->AsLayerMLGPU()->AsContainerLayerMLGPU()) {
root->ComputeIntermediateSurfaceBounds();
}
// Traverse the layer tree and assign each layer to tiles.
{
Maybe<gfx::Polygon> geometry;
RenderTargetIntRect clip(0, 0, target->GetSize().width,
target->GetSize().height);
AssignLayer(mRoot->GetLayer(), mWidgetRenderView, clip,
std::move(geometry));
}
// Build the default mask buffer.
{
MaskInformation defaultMaskInfo(1.0f, false);
if (!mDevice->GetSharedPSBuffer()->Allocate(&mDefaultMaskInfo,
defaultMaskInfo)) {
return false;
}
}
// Build render passes and buffer information for each pass.
mWidgetRenderView->FinishBuilding();
mWidgetRenderView->Prepare();
// Prepare masks that need to be combined.
for (const auto& pair : mCombinedTextureMasks) {
pair.second->PrepareForRendering();
}
FinishCurrentLayerBuffer();
FinishCurrentMaskRectBuffer();
return true;
}
void FrameBuilder::Render() {
AUTO_PROFILER_LABEL("FrameBuilder::Render", GRAPHICS);
// Render combined masks into single mask textures.
for (const auto& pair : mCombinedTextureMasks) {
pair.second->Render();
}
// Render to all targets, front-to-back.
mWidgetRenderView->Render();
}
void FrameBuilder::AssignLayer(Layer* aLayer, RenderViewMLGPU* aView,
const RenderTargetIntRect& aClipRect,
Maybe<gfx::Polygon>&& aGeometry) {
LayerMLGPU* layer = aLayer->AsHostLayer()->AsLayerMLGPU();
if (ContainerLayer* container = aLayer->AsContainerLayer()) {
// This returns false if we don't need to (or can't) process the layer any
// further. This always returns false for non-leaf ContainerLayers.
if (!ProcessContainerLayer(container, aView, aClipRect, aGeometry)) {
return;
}
} else {
// Set the precomputed clip and any textures/resources that are needed.
if (!layer->PrepareToRender(this, aClipRect)) {
return;
}
}
// If we are dealing with a nested 3D context, we might need to transform
// the geometry back to the coordinate space of the current layer.
if (aGeometry) {
TransformLayerGeometry(aLayer, aGeometry);
}
// Finally, assign the layer to a rendering batch in the current render
// target.
layer->AssignToView(this, aView, std::move(aGeometry));
}
bool FrameBuilder::ProcessContainerLayer(ContainerLayer* aContainer,
RenderViewMLGPU* aView,
const RenderTargetIntRect& aClipRect,
Maybe<gfx::Polygon>& aGeometry) {
LayerMLGPU* layer = aContainer->AsHostLayer()->AsLayerMLGPU();
// Diagnostic information for bug 1387467.
if (!layer) {
gfxDevCrash(gfx::LogReason::InvalidLayerType)
<< "Layer type is invalid: " << aContainer->Name();
return false;
}
// We don't want to traverse containers twice, so we only traverse them if
// they haven't been prepared yet.
bool isFirstVisit = !layer->IsPrepared();
if (isFirstVisit && !layer->PrepareToRender(this, aClipRect)) {
return false;
}
if (!aContainer->UseIntermediateSurface()) {
// In case the layer previously required an intermediate surface, we
// clear any intermediate render targets here.
layer->ClearCachedResources();
// This is a pass-through container, so we just process children and
// instruct AssignLayer to early-return.
ProcessChildList(aContainer, aView, aClipRect, aGeometry);
return false;
}
// If this is the first visit of the container this frame, and the
// container has an unpainted area, we traverse the container. Note that
// RefLayers do not have intermediate surfaces so this is guaranteed
// to be a full-fledged ContainerLayerMLGPU.
ContainerLayerMLGPU* viewContainer = layer->AsContainerLayerMLGPU();
if (!viewContainer) {
gfxDevCrash(gfx::LogReason::InvalidLayerType)
<< "Container layer type is invalid: " << aContainer->Name();
return false;
}
if (isFirstVisit && !viewContainer->GetInvalidRect().IsEmpty()) {
// The RenderView constructor automatically attaches itself to the parent.
RefPtr<RenderViewMLGPU> view =
new RenderViewMLGPU(this, viewContainer, aView);
ProcessChildList(aContainer, view, aClipRect, Nothing());
view->FinishBuilding();
}
return true;
}
void FrameBuilder::ProcessChildList(
ContainerLayer* aContainer, RenderViewMLGPU* aView,
const RenderTargetIntRect& aParentClipRect,
const Maybe<gfx::Polygon>& aParentGeometry) {
nsTArray<LayerPolygon> polygons = aContainer->SortChildrenBy3DZOrder(
ContainerLayer::SortMode::WITH_GEOMETRY);
// Visit layers in front-to-back order.
for (auto iter = polygons.rbegin(); iter != polygons.rend(); iter++) {
LayerPolygon& entry = *iter;
Layer* child = entry.layer;
if (child->IsBackfaceHidden() || !child->IsVisible()) {
continue;
}
RenderTargetIntRect clip = child->CalculateScissorRect(aParentClipRect);
if (clip.IsEmpty()) {
continue;
}
Maybe<gfx::Polygon> geometry;
if (aParentGeometry && entry.geometry) {
// Both parent and child are split.
geometry = Some(aParentGeometry->ClipPolygon(*entry.geometry));
} else if (aParentGeometry) {
geometry = aParentGeometry;
} else if (entry.geometry) {
geometry = std::move(entry.geometry);
}
AssignLayer(child, aView, clip, std::move(geometry));
}
}
bool FrameBuilder::AddLayerToConstantBuffer(ItemInfo& aItem) {
LayerMLGPU* layer = aItem.layer;
// If this layer could appear multiple times, cache it.
if (aItem.geometry) {
if (mLayerBufferMap.Get(layer, &aItem.layerIndex)) {
return true;
}
}
LayerConstants* info = AllocateLayerInfo(aItem);
if (!info) {
return false;
}
// Note we do not use GetEffectiveTransformForBuffer, since we calculate
// the correct scaling when we build texture coordinates.
Layer* baseLayer = layer->GetLayer();
const gfx::Matrix4x4& transform = baseLayer->GetEffectiveTransform();
memcpy(&info->transform, &transform._11, 64);
info->clipRect = gfx::Rect(layer->GetComputedClipRect().ToUnknownRect());
info->maskIndex = 0;
if (MaskOperation* op = layer->GetMask()) {
// Note: we use 0 as an invalid index, and so indices are offset by 1.
gfx::Rect rect = op->ComputeMaskRect(baseLayer);
AddMaskRect(rect, &info->maskIndex);
}
if (aItem.geometry) {
mLayerBufferMap.Put(layer, aItem.layerIndex);
}
return true;
}
MaskOperation* FrameBuilder::AddMaskOperation(LayerMLGPU* aLayer) {
Layer* layer = aLayer->GetLayer();
MOZ_ASSERT(layer->HasMaskLayers());
// Multiple masks are combined into a single mask.
if ((layer->GetMaskLayer() && layer->GetAncestorMaskLayerCount()) ||
layer->GetAncestorMaskLayerCount() > 1) {
// Since each mask can be moved independently of the other, we must create
// a separate combined mask for every new positioning we encounter.
MaskTextureList textures;
if (Layer* maskLayer = layer->GetMaskLayer()) {
AppendToMaskTextureList(textures, maskLayer);
}
for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
AppendToMaskTextureList(textures, layer->GetAncestorMaskLayerAt(i));
}
auto iter = mCombinedTextureMasks.find(textures);
if (iter != mCombinedTextureMasks.end()) {
return iter->second;
}
RefPtr<MaskCombineOperation> op = new MaskCombineOperation(this);
op->Init(textures);
mCombinedTextureMasks[textures] = op;
return op;
}
Layer* maskLayer = layer->GetMaskLayer() ? layer->GetMaskLayer()
: layer->GetAncestorMaskLayerAt(0);
RefPtr<TextureSource> texture = GetMaskLayerTexture(maskLayer);
if (!texture) {
return nullptr;
}
RefPtr<MaskOperation> op;
mSingleTextureMasks.Get(texture, getter_AddRefs(op));
if (op) {
return op;
}
RefPtr<MLGTexture> wrapped = mDevice->CreateTexture(texture);
op = new MaskOperation(this, wrapped);
mSingleTextureMasks.Put(texture, RefPtr{op});
return op;
}
void FrameBuilder::RetainTemporaryLayer(LayerMLGPU* aLayer) {
// This should only be used with temporary layers. Temporary layers do not
// have parents.
MOZ_ASSERT(!aLayer->GetLayer()->GetParent());
mTemporaryLayers.push_back(aLayer->GetLayer());
}
MLGRenderTarget* FrameBuilder::GetWidgetRT() {
return mWidgetRenderView->GetRenderTarget();
}
LayerConstants* FrameBuilder::AllocateLayerInfo(ItemInfo& aItem) {
if (((mCurrentLayerBuffer.Length() + 1) * sizeof(LayerConstants)) >
mDevice->GetMaxConstantBufferBindSize()) {
FinishCurrentLayerBuffer();
mLayerBufferMap.Clear();
mCurrentLayerBuffer.ClearAndRetainStorage();
}
LayerConstants* info = mCurrentLayerBuffer.AppendElement(mozilla::fallible);
if (!info) {
return nullptr;
}
aItem.layerIndex = mCurrentLayerBuffer.Length() - 1;
return info;
}
void FrameBuilder::FinishCurrentLayerBuffer() {
if (mCurrentLayerBuffer.IsEmpty()) {
return;
}
// Note: we append the buffer even if we couldn't allocate one, since
// that keeps the indices sane.
ConstantBufferSection section;
mDevice->GetSharedVSBuffer()->Allocate(
&section, mCurrentLayerBuffer.Elements(), mCurrentLayerBuffer.Length());
mLayerBuffers.AppendElement(section);
}
size_t FrameBuilder::CurrentLayerBufferIndex() const {
// The mask rect buffer list doesn't contain the buffer currently being
// built, so we don't subtract 1 here.
return mLayerBuffers.Length();
}
ConstantBufferSection FrameBuilder::GetLayerBufferByIndex(size_t aIndex) const {
if (aIndex >= mLayerBuffers.Length()) {
return ConstantBufferSection();
}
return mLayerBuffers[aIndex];
}
bool FrameBuilder::AddMaskRect(const gfx::Rect& aRect, uint32_t* aOutIndex) {
if (((mCurrentMaskRectList.Length() + 1) * sizeof(gfx::Rect)) >
mDevice->GetMaxConstantBufferBindSize()) {
FinishCurrentMaskRectBuffer();
mCurrentMaskRectList.ClearAndRetainStorage();
}
mCurrentMaskRectList.AppendElement(aRect);
// Mask indices start at 1 so the shader can use 0 as a no-mask indicator.
*aOutIndex = mCurrentMaskRectList.Length();
return true;
}
void FrameBuilder::FinishCurrentMaskRectBuffer() {
if (mCurrentMaskRectList.IsEmpty()) {
return;
}
// Note: we append the buffer even if we couldn't allocate one, since
// that keeps the indices sane.
ConstantBufferSection section;
mDevice->GetSharedVSBuffer()->Allocate(
&section, mCurrentMaskRectList.Elements(), mCurrentMaskRectList.Length());
mMaskRectBuffers.AppendElement(section);
}
size_t FrameBuilder::CurrentMaskRectBufferIndex() const {
// The mask rect buffer list doesn't contain the buffer currently being
// built, so we don't subtract 1 here.
return mMaskRectBuffers.Length();
}
ConstantBufferSection FrameBuilder::GetMaskRectBufferByIndex(
size_t aIndex) const {
if (aIndex >= mMaskRectBuffers.Length()) {
return ConstantBufferSection();
}
return mMaskRectBuffers[aIndex];
}
} // namespace layers
} // namespace mozilla

View File

@ -1,126 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_FrameBuilder_h
#define mozilla_gfx_layers_mlgpu_FrameBuilder_h
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Types.h"
#include "MaskOperation.h"
#include "MLGDevice.h"
#include "nsDataHashtable.h"
#include "nsRefPtrHashtable.h"
#include "ShaderDefinitionsMLGPU.h"
#include "SharedBufferMLGPU.h"
#include "Units.h"
#include <map>
#include <vector>
namespace mozilla {
namespace layers {
class ContainerLayer;
class ContainerLayerMLGPU;
class Layer;
class LayerMLGPU;
class LayerManagerMLGPU;
class MLGDevice;
class MLGRenderTarget;
class MLGSwapChain;
class RenderViewMLGPU;
struct ItemInfo;
class FrameBuilder final {
public:
FrameBuilder(LayerManagerMLGPU* aManager, MLGSwapChain* aSwapChain);
~FrameBuilder();
bool Build();
void Render();
bool AddLayerToConstantBuffer(ItemInfo& aItem);
LayerManagerMLGPU* GetManager() const { return mManager; }
MLGDevice* GetDevice() const { return mDevice; }
const ConstantBufferSection& GetDefaultMaskInfo() const {
return mDefaultMaskInfo;
}
// Called during tile construction. Finds or adds a mask layer chain to the
// cache, that will be flattened as a dependency to rendering batches.
MaskOperation* AddMaskOperation(LayerMLGPU* aLayer);
// Note: These should only be called during batch construction.
size_t CurrentLayerBufferIndex() const;
size_t CurrentMaskRectBufferIndex() const;
// These are called during rendering, and may return null if a buffer
// couldn't be allocated.
ConstantBufferSection GetLayerBufferByIndex(size_t aIndex) const;
ConstantBufferSection GetMaskRectBufferByIndex(size_t aIndex) const;
// Hold a layer alive until the frame ends.
void RetainTemporaryLayer(LayerMLGPU* aLayer);
MLGRenderTarget* GetWidgetRT();
private:
void AssignLayer(Layer* aLayer, RenderViewMLGPU* aView,
const RenderTargetIntRect& aClipRect,
Maybe<gfx::Polygon>&& aGeometry);
void ProcessChildList(ContainerLayer* aContainer, RenderViewMLGPU* aView,
const RenderTargetIntRect& aParentClipRect,
const Maybe<gfx::Polygon>& aParentGeometry);
mlg::LayerConstants* AllocateLayerInfo(ItemInfo& aItem);
bool AddMaskRect(const gfx::Rect& aRect, uint32_t* aOutIndex);
void FinishCurrentLayerBuffer();
void FinishCurrentMaskRectBuffer();
// Returns true to continue, false to stop - false does not indicate
// failure.
bool ProcessContainerLayer(ContainerLayer* aLayer, RenderViewMLGPU* aView,
const RenderTargetIntRect& aClipRect,
Maybe<gfx::Polygon>& aGeometry);
private:
RefPtr<LayerManagerMLGPU> mManager;
RefPtr<MLGDevice> mDevice;
RefPtr<MLGSwapChain> mSwapChain;
RefPtr<RenderViewMLGPU> mWidgetRenderView;
LayerMLGPU* mRoot;
// Each time we consume a layer in a tile, we make sure a constant buffer
// exists that contains information about the layer. The mapping is valid
// for the most recent buffer, and once the buffer fills, we begin a new
// one and clear the map.
nsTArray<ConstantBufferSection> mLayerBuffers;
nsTArray<mlg::LayerConstants> mCurrentLayerBuffer;
nsDataHashtable<nsPtrHashKey<LayerMLGPU>, uint32_t> mLayerBufferMap;
// We keep mask rects in a separate buffer since they're rare.
nsTArray<ConstantBufferSection> mMaskRectBuffers;
nsTArray<gfx::Rect> mCurrentMaskRectList;
// For values that *can* change every render pass, but almost certainly do
// not, we pre-fill and cache some buffers.
ConstantBufferSection mDefaultMaskInfo;
// Cache for MaskOperations.
nsRefPtrHashtable<nsRefPtrHashKey<TextureSource>, MaskOperation>
mSingleTextureMasks;
std::map<MaskTextureList, RefPtr<MaskCombineOperation>> mCombinedTextureMasks;
// This list of temporary layers is wiped out when the frame is completed.
std::vector<RefPtr<Layer>> mTemporaryLayers;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_FrameBuilder_h

View File

@ -1,108 +0,0 @@
/* -*- 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 "ImageLayerMLGPU.h"
#include "LayerManagerMLGPU.h"
namespace mozilla {
using namespace gfx;
namespace layers {
ImageLayerMLGPU::ImageLayerMLGPU(LayerManagerMLGPU* aManager)
: ImageLayer(aManager, static_cast<HostLayer*>(this)),
TexturedLayerMLGPU(aManager) {}
ImageLayerMLGPU::~ImageLayerMLGPU() { CleanupResources(); }
void ImageLayerMLGPU::ComputeEffectiveTransforms(
const gfx::Matrix4x4& aTransformToSurface) {
Matrix4x4 local = GetLocalTransform();
// Snap image edges to pixel boundaries.
gfxRect sourceRect(0, 0, 0, 0);
if (mHost && mHost->IsAttached()) {
IntSize size = mHost->GetImageSize();
sourceRect.SizeTo(size.width, size.height);
}
// Snap our local transform first, and snap the inherited transform as well.
// This makes our snapping equivalent to what would happen if our content
// was drawn into a PaintedLayer (gfxContext would snap using the local
// transform, then we'd snap again when compositing the PaintedLayer).
mEffectiveTransform = SnapTransform(local, sourceRect, nullptr) *
SnapTransformTranslation(aTransformToSurface, nullptr);
mEffectiveTransformForBuffer = mEffectiveTransform;
if (mScaleMode == ScaleMode::STRETCH && mScaleToSize.width != 0.0 &&
mScaleToSize.height != 0.0) {
Size scale(sourceRect.Width() / mScaleToSize.width,
sourceRect.Height() / mScaleToSize.height);
mScale = Some(scale);
}
ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
}
gfx::SamplingFilter ImageLayerMLGPU::GetSamplingFilter() {
return ImageLayer::GetSamplingFilter();
}
bool ImageLayerMLGPU::IsContentOpaque() {
if (mPictureRect.Width() == 0 || mPictureRect.Height() == 0) {
return false;
}
if (mScaleMode == ScaleMode::STRETCH) {
return gfx::IsOpaque(mHost->CurrentTextureHost()->GetFormat());
}
return false;
}
void ImageLayerMLGPU::SetRenderRegion(LayerIntRegion&& aRegion) {
switch (mScaleMode) {
case ScaleMode::STRETCH:
// See bug 1264142.
aRegion.AndWith(
LayerIntRect(0, 0, mScaleToSize.width, mScaleToSize.height));
break;
default:
// Clamp the visible region to the texture size. (see bug 1396507)
MOZ_ASSERT(mScaleMode == ScaleMode::SCALE_NONE);
aRegion.AndWith(
LayerIntRect(0, 0, mPictureRect.Width(), mPictureRect.Height()));
break;
}
LayerMLGPU::SetRenderRegion(std::move(aRegion));
}
void ImageLayerMLGPU::CleanupResources() {
if (mHost) {
mHost->CleanupResources();
mHost->Detach(this);
}
mTexture = nullptr;
mBigImageTexture = nullptr;
mHost = nullptr;
}
void ImageLayerMLGPU::PrintInfo(std::stringstream& aStream,
const char* aPrefix) {
ImageLayer::PrintInfo(aStream, aPrefix);
if (mHost && mHost->IsAttached()) {
aStream << "\n";
nsAutoCString pfx(aPrefix);
pfx += " ";
mHost->PrintInfo(aStream, pfx.get());
}
}
void ImageLayerMLGPU::Disconnect() { CleanupResources(); }
void ImageLayerMLGPU::ClearCachedResources() { CleanupResources(); }
} // namespace layers
} // namespace mozilla

View File

@ -1,51 +0,0 @@
/* -*- 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_GFX_IMAGELAYERMLGPU_H
#define MOZILLA_GFX_IMAGELAYERMLGPU_H
#include "LayerManagerMLGPU.h"
#include "TexturedLayerMLGPU.h"
#include "ImageLayers.h"
#include "mozilla/layers/ImageHost.h"
namespace mozilla {
namespace layers {
class ImageLayerMLGPU final : public ImageLayer, public TexturedLayerMLGPU {
public:
explicit ImageLayerMLGPU(LayerManagerMLGPU* aManager);
Layer* GetLayer() override { return this; }
HostLayer* AsHostLayer() override { return this; }
ImageLayerMLGPU* AsImageLayerMLGPU() override { return this; }
void ComputeEffectiveTransforms(
const gfx::Matrix4x4& aTransformToSurface) override;
void SetRenderRegion(LayerIntRegion&& aRegion) override;
gfx::SamplingFilter GetSamplingFilter() override;
void ClearCachedResources() override;
bool IsContentOpaque() override;
void Disconnect() override;
Maybe<gfx::Size> GetPictureScale() const override { return mScale; }
MOZ_LAYER_DECL_NAME("ImageLayerMLGPU", TYPE_IMAGE)
protected:
virtual ~ImageLayerMLGPU();
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
void CleanupResources();
private:
Maybe<gfx::Size> mScale;
};
} // namespace layers
} // namespace mozilla
#endif

View File

@ -1,141 +0,0 @@
/* -*- 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 "LayerManagerMLGPU.h"
#include "RenderPassMLGPU.h"
#include "RenderViewMLGPU.h"
#include "FrameBuilder.h"
#include "mozilla/layers/ImageHost.h"
#include "mozilla/layers/LayerManagerComposite.h"
namespace mozilla {
namespace layers {
using namespace gfx;
uint64_t LayerMLGPU::sFrameKey = 0;
LayerMLGPU::~LayerMLGPU() = default;
LayerMLGPU::LayerMLGPU(LayerManagerMLGPU* aManager)
: HostLayer(aManager),
mFrameKey(0),
mComputedOpacity(0.0),
mPrepared(false) {}
/* static */
void LayerMLGPU::BeginFrame() { sFrameKey++; }
LayerManagerMLGPU* LayerMLGPU::GetManager() {
return static_cast<LayerManagerMLGPU*>(mCompositorManager);
}
bool LayerMLGPU::PrepareToRender(FrameBuilder* aBuilder,
const RenderTargetIntRect& aClipRect) {
if (mFrameKey == sFrameKey) {
return mPrepared;
}
mFrameKey = sFrameKey;
mPrepared = false;
Layer* layer = GetLayer();
// Only container layers may have mixed blend modes.
MOZ_ASSERT_IF(layer->GetMixBlendMode() != CompositionOp::OP_OVER,
layer->GetType() == Layer::TYPE_CONTAINER);
mComputedClipRect = aClipRect;
mComputedOpacity = layer->GetEffectiveOpacity();
if (layer->HasMaskLayers()) {
mMask = aBuilder->AddMaskOperation(this);
// If the mask has no texture, the pixel shader can't read any non-zero
// values for the mask, so we can consider the whole thing invisible.
if (mMask && mMask->IsEmpty()) {
mComputedOpacity = 0.0f;
}
} else {
mMask = nullptr;
}
if (!OnPrepareToRender(aBuilder)) {
return false;
}
mPrepared = true;
return true;
}
void LayerMLGPU::AssignToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
Maybe<gfx::Polygon>&& aGeometry) {
AddBoundsToView(aBuilder, aView, std::move(aGeometry));
}
void LayerMLGPU::AddBoundsToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
Maybe<gfx::Polygon>&& aGeometry) {
IntRect bounds = GetClippedBoundingBox(aView, aGeometry);
aView->AddItem(this, bounds, std::move(aGeometry));
}
IntRect LayerMLGPU::GetClippedBoundingBox(
RenderViewMLGPU* aView, const Maybe<gfx::Polygon>& aGeometry) {
MOZ_ASSERT(IsPrepared());
Layer* layer = GetLayer();
const Matrix4x4& transform = layer->GetEffectiveTransform();
Rect rect =
aGeometry
? aGeometry->BoundingBox()
: Rect(layer->GetLocalVisibleRegion().GetBounds().ToUnknownRect());
rect = transform.TransformBounds(rect);
rect.MoveBy(-aView->GetTargetOffset());
rect = rect.Intersect(Rect(mComputedClipRect.ToUnknownRect()));
IntRect bounds;
rect.RoundOut();
rect.ToIntRect(&bounds);
return bounds;
}
void LayerMLGPU::MarkPrepared() {
mFrameKey = sFrameKey;
mPrepared = true;
}
bool LayerMLGPU::IsContentOpaque() { return GetLayer()->IsOpaque(); }
void LayerMLGPU::SetRenderRegion(LayerIntRegion&& aRegion) {
mRenderRegion = std::move(aRegion);
}
void LayerMLGPU::SetLayerManager(HostLayerManager* aManager) {
LayerManagerMLGPU* manager = aManager->AsLayerManagerMLGPU();
MOZ_RELEASE_ASSERT(manager);
HostLayer::SetLayerManager(aManager);
GetLayer()->SetManager(manager, this);
if (CompositableHost* host = GetCompositableHost()) {
host->SetTextureSourceProvider(manager->GetTextureSourceProvider());
}
OnLayerManagerChange(manager);
}
RefLayerMLGPU::RefLayerMLGPU(LayerManagerMLGPU* aManager)
: RefLayer(aManager, static_cast<HostLayer*>(this)), LayerMLGPU(aManager) {}
RefLayerMLGPU::~RefLayerMLGPU() = default;
ColorLayerMLGPU::ColorLayerMLGPU(LayerManagerMLGPU* aManager)
: ColorLayer(aManager, static_cast<HostLayer*>(this)),
LayerMLGPU(aManager) {}
ColorLayerMLGPU::~ColorLayerMLGPU() = default;
} // namespace layers
} // namespace mozilla

View File

@ -1,161 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_LayerMLGPU_h
#define mozilla_gfx_layers_mlgpu_LayerMLGPU_h
#include "Layers.h"
#include "mozilla/layers/LayerManagerComposite.h"
namespace mozilla {
namespace layers {
class CanvasLayerMLGPU;
class ColorLayerMLGPU;
class ContainerLayerMLGPU;
class FrameBuilder;
class ImageHost;
class ImageLayerMLGPU;
class LayerManagerMLGPU;
class MaskOperation;
class MLGRenderTarget;
class PaintedLayerMLGPU;
class RefLayerMLGPU;
class RenderViewMLGPU;
class TexturedLayerMLGPU;
class TextureSource;
class LayerMLGPU : public HostLayer {
public:
LayerMLGPU* AsLayerMLGPU() override { return this; }
virtual PaintedLayerMLGPU* AsPaintedLayerMLGPU() { return nullptr; }
virtual ImageLayerMLGPU* AsImageLayerMLGPU() { return nullptr; }
virtual CanvasLayerMLGPU* AsCanvasLayerMLGPU() { return nullptr; }
virtual ContainerLayerMLGPU* AsContainerLayerMLGPU() { return nullptr; }
virtual RefLayerMLGPU* AsRefLayerMLGPU() { return nullptr; }
virtual ColorLayerMLGPU* AsColorLayerMLGPU() { return nullptr; }
virtual TexturedLayerMLGPU* AsTexturedLayerMLGPU() { return nullptr; }
static void BeginFrame();
// Ask the layer to acquire any resources or per-frame information needed
// to render. If this returns false, the layer will be skipped entirely.
bool PrepareToRender(FrameBuilder* aBuilder,
const RenderTargetIntRect& aClipRect);
Layer::LayerType GetType() { return GetLayer()->GetType(); }
const RenderTargetIntRect& GetComputedClipRect() const {
return mComputedClipRect;
}
MaskOperation* GetMask() const { return mMask; }
float GetComputedOpacity() const { return mComputedOpacity; }
// Return the bounding box of this layer in render target space, clipped to
// the computed clip rect, and rounded out to an integer rect.
gfx::IntRect GetClippedBoundingBox(RenderViewMLGPU* aView,
const Maybe<gfx::Polygon>& aGeometry);
// If this layer has already been prepared for the current frame, return
// true. This should only be used to guard against double-processing
// container layers after 3d-sorting.
bool IsPrepared() const { return mFrameKey == sFrameKey && mPrepared; }
// Return true if the content in this layer is opaque (not factoring in
// blend modes or opacity), false otherwise.
virtual bool IsContentOpaque();
// Returns the region that this layer will draw pixels to. If the layer and
// its content are opaque, this is the layer's opaque region.
const LayerIntRegion& GetRenderRegion() const { return mRenderRegion; }
// Some layers have visible regions that extend beyond what is actually drawn.
// When performing CPU-based occlusion culling we must clamp the visible
// region to the actual area. Note that if a layer is opaque, it must not
// expand its visible region such that it might include non-opaque pixels, as
// may be the case for PaintedLayers with a restricted visible region.
virtual void SetRenderRegion(LayerIntRegion&& aRegion);
virtual void AssignToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
Maybe<gfx::Polygon>&& aGeometry);
// Callback for when PrepareToRender has finished successfully. If this
// returns false, PrepareToRender will return false.
virtual bool OnPrepareToRender(FrameBuilder* aBuilder) { return true; }
virtual void ClearCachedResources() {}
CompositableHost* GetCompositableHost() override { return nullptr; }
protected:
LayerMLGPU(LayerManagerMLGPU* aManager);
~LayerMLGPU();
LayerManagerMLGPU* GetManager();
void AddBoundsToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
Maybe<gfx::Polygon>&& aGeometry);
void MarkPrepared();
// We don't want derivative layers overriding this directly - we provide a
// callback instead.
void SetLayerManager(HostLayerManager* aManager) override;
virtual void OnLayerManagerChange(LayerManagerMLGPU* aManager) {}
private:
// This is a monotonic counter used to check whether a layer appears twice
// when 3d sorting.
static uint64_t sFrameKey;
protected:
// These are set during PrepareToRender.
RenderTargetIntRect mComputedClipRect;
RefPtr<MaskOperation> mMask;
uint64_t mFrameKey;
float mComputedOpacity;
bool mPrepared;
LayerIntRegion mRenderRegion;
};
class RefLayerMLGPU final : public RefLayer, public LayerMLGPU {
public:
explicit RefLayerMLGPU(LayerManagerMLGPU* aManager);
virtual ~RefLayerMLGPU();
// Layer
HostLayer* AsHostLayer() override { return this; }
RefLayerMLGPU* AsRefLayerMLGPU() override { return this; }
Layer* GetLayer() override { return this; }
// ContainerLayer
void ComputeEffectiveTransforms(
const gfx::Matrix4x4& aTransformToSurface) override {
DefaultComputeEffectiveTransforms(aTransformToSurface);
}
const LayerIntRegion& GetShadowVisibleRegion() override;
MOZ_LAYER_DECL_NAME("RefLayerMLGPU", TYPE_REF)
};
class ColorLayerMLGPU final : public ColorLayer, public LayerMLGPU {
public:
explicit ColorLayerMLGPU(LayerManagerMLGPU* aManager);
virtual ~ColorLayerMLGPU();
// LayerMLGPU
bool IsContentOpaque() override { return mColor.a >= 1.0f; }
// Layer
HostLayer* AsHostLayer() override { return this; }
ColorLayerMLGPU* AsColorLayerMLGPU() override { return this; }
Layer* GetLayer() override { return this; }
MOZ_LAYER_DECL_NAME("ColorLayerMLGPU", TYPE_COLOR)
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_LayerMLGPU_h

View File

@ -1,588 +0,0 @@
/* -*- 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 "LayerManagerMLGPU.h"
#include "LayerTreeInvalidation.h"
#include "PaintedLayerMLGPU.h"
#include "ImageLayerMLGPU.h"
#include "CanvasLayerMLGPU.h"
#include "ContainerLayerMLGPU.h"
#include "GeckoProfiler.h" // for profiler_*
#include "gfxEnv.h" // for gfxEnv
#include "MLGDevice.h"
#include "RenderPassMLGPU.h"
#include "RenderViewMLGPU.h"
#include "ShaderDefinitionsMLGPU.h"
#include "SharedBufferMLGPU.h"
#include "UnitTransforms.h"
#include "TextureSourceProviderMLGPU.h"
#include "TreeTraversal.h"
#include "FrameBuilder.h"
#include "UtilityMLGPU.h"
#include "CompositionRecorder.h"
#include "mozilla/layers/Diagnostics.h"
#include "mozilla/layers/TextRenderer.h"
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/ToString.h"
#ifdef XP_WIN
# include "mozilla/widget/WinCompositorWidget.h"
# include "mozilla/gfx/DeviceManagerDx.h"
#endif
namespace mozilla {
namespace layers {
using namespace gfx;
static const int kDebugOverlayX = 2;
static const int kDebugOverlayY = 5;
static const int kDebugOverlayMaxWidth = 600;
static const int kDebugOverlayMaxHeight = 96;
class RecordedFrameMLGPU : public RecordedFrame {
public:
RecordedFrameMLGPU(MLGDevice* aDevice, MLGTexture* aTexture,
const TimeStamp& aTimestamp)
: RecordedFrame(aTimestamp), mDevice(aDevice) {
mSoftTexture =
aDevice->CreateTexture(aTexture->GetSize(), SurfaceFormat::B8G8R8A8,
MLGUsage::Staging, MLGTextureFlags::None);
aDevice->CopyTexture(mSoftTexture, IntPoint(), aTexture,
IntRect(IntPoint(), aTexture->GetSize()));
}
~RecordedFrameMLGPU() {
if (mIsMapped) {
mDevice->Unmap(mSoftTexture);
}
}
virtual already_AddRefed<gfx::DataSourceSurface> GetSourceSurface() override {
if (mDataSurf) {
return RefPtr<DataSourceSurface>(mDataSurf).forget();
}
MLGMappedResource map;
if (!mDevice->Map(mSoftTexture, MLGMapType::READ, &map)) {
return nullptr;
}
mIsMapped = true;
mDataSurf = Factory::CreateWrappingDataSourceSurface(
map.mData, map.mStride, mSoftTexture->GetSize(),
SurfaceFormat::B8G8R8A8);
return RefPtr<DataSourceSurface>(mDataSurf).forget();
}
private:
RefPtr<MLGDevice> mDevice;
// Software texture in VRAM.
RefPtr<MLGTexture> mSoftTexture;
RefPtr<DataSourceSurface> mDataSurf;
bool mIsMapped = false;
};
LayerManagerMLGPU::LayerManagerMLGPU(widget::CompositorWidget* aWidget)
: mWidget(aWidget),
mDrawDiagnostics(false),
mUsingInvalidation(false),
mCurrentFrame(nullptr),
mDebugFrameNumber(0) {
if (!aWidget) {
return;
}
#ifdef WIN32
mDevice = DeviceManagerDx::Get()->GetMLGDevice();
#endif
if (!mDevice || !mDevice->IsValid()) {
gfxWarning() << "Could not acquire an MLGDevice!";
return;
}
mSwapChain = mDevice->CreateSwapChainForWidget(aWidget);
if (!mSwapChain) {
gfxWarning() << "Could not acquire an MLGSwapChain!";
return;
}
mDiagnostics = MakeUnique<Diagnostics>();
mTextRenderer = new TextRenderer();
}
LayerManagerMLGPU::~LayerManagerMLGPU() {
if (mTextureSourceProvider) {
mTextureSourceProvider->Destroy();
}
}
bool LayerManagerMLGPU::Initialize() {
if (!mDevice || !mSwapChain) {
return false;
}
mTextureSourceProvider = new TextureSourceProviderMLGPU(this, mDevice);
return true;
}
void LayerManagerMLGPU::Destroy() {
if (IsDestroyed()) {
return;
}
LayerManager::Destroy();
mProfilerScreenshotGrabber.Destroy();
if (mDevice && mDevice->IsValid()) {
mDevice->Flush();
}
if (mSwapChain) {
mSwapChain->Destroy();
mSwapChain = nullptr;
}
if (mTextureSourceProvider) {
mTextureSourceProvider->Destroy();
mTextureSourceProvider = nullptr;
}
mWidget = nullptr;
mDevice = nullptr;
}
void LayerManagerMLGPU::ForcePresent() {
if (!mDevice->IsValid()) {
return;
}
IntSize windowSize = mWidget->GetClientSize().ToUnknownSize();
if (mSwapChain->GetSize() != windowSize) {
return;
}
mSwapChain->ForcePresent();
}
already_AddRefed<ContainerLayer> LayerManagerMLGPU::CreateContainerLayer() {
return MakeAndAddRef<ContainerLayerMLGPU>(this);
}
already_AddRefed<ColorLayer> LayerManagerMLGPU::CreateColorLayer() {
return MakeAndAddRef<ColorLayerMLGPU>(this);
}
already_AddRefed<RefLayer> LayerManagerMLGPU::CreateRefLayer() {
return MakeAndAddRef<RefLayerMLGPU>(this);
}
already_AddRefed<PaintedLayer> LayerManagerMLGPU::CreatePaintedLayer() {
return MakeAndAddRef<PaintedLayerMLGPU>(this);
}
already_AddRefed<ImageLayer> LayerManagerMLGPU::CreateImageLayer() {
return MakeAndAddRef<ImageLayerMLGPU>(this);
}
already_AddRefed<CanvasLayer> LayerManagerMLGPU::CreateCanvasLayer() {
return MakeAndAddRef<CanvasLayerMLGPU>(this);
}
TextureFactoryIdentifier LayerManagerMLGPU::GetTextureFactoryIdentifier() {
TextureFactoryIdentifier ident;
if (mDevice) {
ident = mDevice->GetTextureFactoryIdentifier(mWidget);
}
ident.mUsingAdvancedLayers = true;
return ident;
}
LayersBackend LayerManagerMLGPU::GetBackendType() {
return mDevice ? mDevice->GetLayersBackend() : LayersBackend::LAYERS_NONE;
}
void LayerManagerMLGPU::SetRoot(Layer* aLayer) { mRoot = aLayer; }
bool LayerManagerMLGPU::BeginTransaction(const nsCString& aURL) { return true; }
void LayerManagerMLGPU::BeginTransactionWithDrawTarget(
gfx::DrawTarget* aTarget, const gfx::IntRect& aRect) {
MOZ_ASSERT(!mTarget);
mTarget = aTarget;
mTargetRect = aRect;
}
// Helper class for making sure textures are unlocked.
class MOZ_STACK_CLASS AutoUnlockAllTextures final {
public:
explicit AutoUnlockAllTextures(MLGDevice* aDevice) : mDevice(aDevice) {}
~AutoUnlockAllTextures() { mDevice->UnlockAllTextures(); }
private:
RefPtr<MLGDevice> mDevice;
};
void LayerManagerMLGPU::EndTransaction(const TimeStamp& aTimeStamp,
EndTransactionFlags aFlags) {
AUTO_PROFILER_LABEL("LayerManager::EndTransaction", GRAPHICS);
TextureSourceProvider::AutoReadUnlockTextures unlock(mTextureSourceProvider);
if (!mRoot || (aFlags & END_NO_IMMEDIATE_REDRAW) || !mWidget) {
return;
}
if (!mDevice->IsValid()) {
// Waiting device reset handling.
return;
}
mCompositionOpportunityId = mCompositionOpportunityId.Next();
SetCompositionTime(aTimeStamp);
mCompositionStartTime = TimeStamp::Now();
IntSize windowSize = mWidget->GetClientSize().ToUnknownSize();
if (windowSize.IsEmpty()) {
return;
}
// Resize the window if needed.
#ifdef XP_WIN
mWidget->AsWindows()->UpdateCompositorWndSizeIfNecessary();
#endif
if (mSwapChain->GetSize() != windowSize) {
// Note: all references to the backbuffer must be cleared.
mDevice->SetRenderTarget(nullptr);
if (!mSwapChain->ResizeBuffers(windowSize)) {
gfxCriticalNote << "Could not resize the swapchain ("
<< hexa(windowSize.width) << ","
<< hexa(windowSize.height) << ")";
return;
}
}
// Don't draw the diagnostic overlay if we want to snapshot the output.
mDrawDiagnostics = StaticPrefs::layers_acceleration_draw_fps() && !mTarget;
mUsingInvalidation = StaticPrefs::layers_mlgpu_enable_invalidation();
mDebugFrameNumber++;
AL_LOG("--- Compositing frame %d ---\n", mDebugFrameNumber);
// Compute transforms - and the changed area, if enabled.
mRoot->ComputeEffectiveTransforms(Matrix4x4());
ComputeInvalidRegion();
// Build and execute draw commands, and present.
if (PreRender()) {
Composite();
PostRender();
}
mTextureSourceProvider->FlushPendingNotifyNotUsed();
// Finish composition.
mLastCompositionEndTime = TimeStamp::Now();
}
void LayerManagerMLGPU::Composite() {
if (gfxEnv::SkipComposition()) {
return;
}
AUTO_PROFILER_LABEL("LayerManagerMLGPU::Composite", GRAPHICS);
// Don't composite if we're minimized/hidden, or if there is nothing to draw.
if (mWidget->IsHidden()) {
return;
}
// Make sure the diagnostic area gets invalidated. We do this now, rather than
// earlier, so we don't accidentally cause extra composites.
Maybe<IntRect> diagnosticRect;
if (mDrawDiagnostics) {
diagnosticRect =
Some(IntRect(kDebugOverlayX, kDebugOverlayY, kDebugOverlayMaxWidth,
kDebugOverlayMaxHeight));
}
AL_LOG("Computed invalid region: %s\n", Stringify(mInvalidRegion).c_str());
// Now that we have the final invalid region, give it to the swap chain which
// will tell us if we still need to render.
if (!mSwapChain->ApplyNewInvalidRegion(std::move(mInvalidRegion),
diagnosticRect)) {
mProfilerScreenshotGrabber.NotifyEmptyFrame();
// Discard the current payloads. These payloads did not require a composite
// (they caused no changes to anything visible), so we don't want to measure
// their latency.
mPayload.Clear();
return;
}
AutoUnlockAllTextures autoUnlock(mDevice);
mDevice->BeginFrame();
RenderLayers();
if (mDrawDiagnostics) {
DrawDebugOverlay();
}
if (mTarget) {
mSwapChain->CopyBackbuffer(mTarget, mTargetRect);
mTarget = nullptr;
mTargetRect = IntRect();
}
mSwapChain->Present();
// We call this here to mimic the behavior in LayerManagerComposite, as to
// not change what Talos measures. That is, we do not record an empty frame
// as a frame, since we short-circuit at the top of this function.
RecordFrame();
mDevice->EndFrame();
// Free the old cloned property tree, then clone a new one. Note that we do
// this after compositing, since layer preparation actually mutates the layer
// tree (for example, ImageHost::mLastFrameID). We want the property tree to
// pick up these changes. Similarly, we are careful to not mutate the tree
// in any way that we *don't* want LayerProperties to catch, lest we cause
// extra invalidation.
//
// Note that the old Compositor performs occlusion culling directly on the
// shadow visible region, and does this *before* cloning layer tree
// properties. Advanced Layers keeps the occlusion region separate and
// performs invalidation against the clean layer tree.
mClonedLayerTreeProperties = nullptr;
mClonedLayerTreeProperties = LayerProperties::CloneFrom(mRoot);
PayloadPresented(TimeStamp::Now());
mPayload.Clear();
}
void LayerManagerMLGPU::RenderLayers() {
AUTO_PROFILER_LABEL("LayerManagerMLGPU::RenderLayers", GRAPHICS);
// Traverse the layer tree and assign each layer to a render target.
FrameBuilder builder(this, mSwapChain);
mCurrentFrame = &builder;
if (!builder.Build()) {
return;
}
if (mDrawDiagnostics) {
mDiagnostics->RecordPrepareTime(
(TimeStamp::Now() - mCompositionStartTime).ToMilliseconds());
}
// Make sure we acquire/release the sync object.
if (!mDevice->Synchronize()) {
// Catastrophic failure - probably a device reset.
return;
}
TimeStamp start = TimeStamp::Now();
// Upload shared buffers.
mDevice->FinishSharedBufferUse();
// Prepare the pipeline.
if (mDrawDiagnostics) {
IntSize size = mSwapChain->GetBackBufferInvalidRegion().GetBounds().Size();
uint32_t numPixels = size.width * size.height;
mDevice->StartDiagnostics(numPixels);
}
// Execute all render passes.
builder.Render();
mProfilerScreenshotGrabber.MaybeGrabScreenshot(
mDevice, builder.GetWidgetRT()->GetTexture());
if (mCompositionRecorder) {
bool hasContentPaint = false;
for (CompositionPayload& payload : mPayload) {
if (payload.mType == CompositionPayloadType::eContentPaint) {
hasContentPaint = true;
break;
}
}
if (hasContentPaint) {
RefPtr<RecordedFrame> frame = new RecordedFrameMLGPU(
mDevice, builder.GetWidgetRT()->GetTexture(), TimeStamp::Now());
mCompositionRecorder->RecordFrame(frame);
}
}
mCurrentFrame = nullptr;
if (mDrawDiagnostics) {
mDiagnostics->RecordCompositeTime(
(TimeStamp::Now() - start).ToMilliseconds());
mDevice->EndDiagnostics();
}
}
void LayerManagerMLGPU::DrawDebugOverlay() {
IntSize windowSize = mSwapChain->GetSize();
GPUStats stats;
mDevice->GetDiagnostics(&stats);
stats.mScreenPixels = windowSize.width * windowSize.height;
std::string text = mDiagnostics->GetFrameOverlayString(stats);
RefPtr<TextureSource> texture = mTextRenderer->RenderText(
mTextureSourceProvider, text, 600, TextRenderer::FontType::FixedWidth);
if (!texture) {
return;
}
if (mUsingInvalidation &&
(texture->GetSize().width > kDebugOverlayMaxWidth ||
texture->GetSize().height > kDebugOverlayMaxHeight)) {
gfxCriticalNote << "Diagnostic overlay exceeds invalidation area: %s"
<< ToString(texture->GetSize()).c_str();
}
struct DebugRect {
Rect bounds;
Rect texCoords;
};
if (!mDiagnosticVertices) {
DebugRect rect;
rect.bounds =
Rect(Point(kDebugOverlayX, kDebugOverlayY), Size(texture->GetSize()));
rect.texCoords = Rect(0.0, 0.0, 1.0, 1.0);
VertexStagingBuffer instances;
if (!instances.AppendItem(rect)) {
return;
}
mDiagnosticVertices = mDevice->CreateBuffer(
MLGBufferType::Vertex, instances.NumItems() * instances.SizeOfItem(),
MLGUsage::Immutable, instances.GetBufferStart());
if (!mDiagnosticVertices) {
return;
}
}
// Note: we rely on the world transform being correctly left bound by the
// outermost render view.
mDevice->SetScissorRect(Nothing());
mDevice->SetDepthTestMode(MLGDepthTestMode::Disabled);
mDevice->SetTopology(MLGPrimitiveTopology::UnitQuad);
mDevice->SetVertexShader(VertexShaderID::DiagnosticText);
mDevice->SetVertexBuffer(1, mDiagnosticVertices, sizeof(DebugRect));
mDevice->SetPixelShader(PixelShaderID::DiagnosticText);
mDevice->SetBlendState(MLGBlendState::Over);
mDevice->SetPSTexture(0, texture);
mDevice->SetSamplerMode(0, SamplerMode::Point);
mDevice->DrawInstanced(4, 1, 0, 0);
}
void LayerManagerMLGPU::ComputeInvalidRegion() {
// If invalidation is disabled, throw away cloned properties and redraw the
// whole target area.
if (!mUsingInvalidation) {
mInvalidRegion = mTarget ? mTargetRect : mRenderBounds;
mNextFrameInvalidRegion.SetEmpty();
return;
}
nsIntRegion changed;
if (mClonedLayerTreeProperties) {
if (!mClonedLayerTreeProperties->ComputeDifferences(mRoot, changed,
nullptr)) {
changed = mRenderBounds;
}
} else {
changed = mRenderBounds;
}
// We compute the change region, but if we're painting to a target, we save
// it for the next frame instead.
if (mTarget) {
mInvalidRegion = mTargetRect;
mNextFrameInvalidRegion.OrWith(changed);
} else {
mInvalidRegion = std::move(mNextFrameInvalidRegion);
mInvalidRegion.OrWith(changed);
}
}
void LayerManagerMLGPU::AddInvalidRegion(const nsIntRegion& aRegion) {
mNextFrameInvalidRegion.OrWith(aRegion);
}
TextureSourceProvider* LayerManagerMLGPU::GetTextureSourceProvider() const {
return mTextureSourceProvider;
}
bool LayerManagerMLGPU::IsCompositingToScreen() const { return !mTarget; }
bool LayerManagerMLGPU::AreComponentAlphaLayersEnabled() {
return LayerManager::AreComponentAlphaLayersEnabled();
}
bool LayerManagerMLGPU::BlendingRequiresIntermediateSurface() { return true; }
void LayerManagerMLGPU::EndTransaction(DrawPaintedLayerCallback aCallback,
void* aCallbackData,
EndTransactionFlags aFlags) {
MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)");
}
void LayerManagerMLGPU::ClearCachedResources(Layer* aSubtree) {
Layer* root = aSubtree ? aSubtree : mRoot.get();
if (!root) {
return;
}
ForEachNode<ForwardIterator>(root, [](Layer* aLayer) {
LayerMLGPU* layer = aLayer->AsHostLayer()->AsLayerMLGPU();
if (!layer) {
return;
}
layer->ClearCachedResources();
});
}
void LayerManagerMLGPU::NotifyShadowTreeTransaction() {
if (StaticPrefs::layers_acceleration_draw_fps()) {
mDiagnostics->AddTxnFrame();
}
}
void LayerManagerMLGPU::UpdateRenderBounds(const gfx::IntRect& aRect) {
mRenderBounds = aRect;
}
bool LayerManagerMLGPU::PreRender() {
AUTO_PROFILER_LABEL("LayerManagerMLGPU::PreRender", GRAPHICS);
widget::WidgetRenderingContext context;
if (!mWidget->PreRender(&context)) {
return false;
}
mWidgetContext = Some(context);
return true;
}
void LayerManagerMLGPU::PostRender() {
mWidget->PostRender(mWidgetContext.ptr());
mProfilerScreenshotGrabber.MaybeProcessQueue();
mWidgetContext = Nothing();
}
} // namespace layers
} // namespace mozilla

View File

@ -1,145 +0,0 @@
/* -*- 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_GFX_LAYERMANAGERMLGPU_H
#define MOZILLA_GFX_LAYERMANAGERMLGPU_H
#include <cstdint> // for uint32_t
#include "mozilla/AlreadyAddRefed.h" // for already_AddRefed
#include "mozilla/Assertions.h" // for AssertionConditionType, MOZ_ASSERT, MOZ_ASSERT_HELPER1
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/UniquePtr.h" // for UniquePtr
#include "mozilla/gfx/Rect.h" // for IntRect
#include "mozilla/layers/CompositorTypes.h" // for TextureFactoryIdentifier
#include "mozilla/layers/LayerManager.h" // for LayerManager::EndTransactionFlags, LayerManager::DrawPaintedLayerCallback
#include "mozilla/layers/LayerManagerComposite.h" // for HostLayerManager
#include "mozilla/layers/LayersTypes.h" // for LayersBackend
#include "mozilla/layers/MLGPUScreenshotGrabber.h" // for MLGPUScreenshotGrabber
#include "nsRegion.h" // for nsIntRegion
#include "nsStringFwd.h" // for nsCString
namespace mozilla {
namespace layers {
class FrameBuilder;
class RenderPassMLGPU;
class SharedBufferMLGPU;
class TextRenderer;
class TextureSourceProviderMLGPU;
class MLGBuffer;
class MLGDevice;
class MLGSwapChain;
class MLGTileBuffer;
struct LayerProperties;
class LayerManagerMLGPU final : public HostLayerManager {
public:
explicit LayerManagerMLGPU(widget::CompositorWidget* aWidget);
virtual ~LayerManagerMLGPU();
bool Initialize();
void Destroy() override;
// LayerManager methods
bool BeginTransaction(const nsCString& aURL) override;
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
const gfx::IntRect& aRect) override;
void SetRoot(Layer* aLayer) override;
already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
already_AddRefed<ContainerLayer> CreateContainerLayer() override;
already_AddRefed<ImageLayer> CreateImageLayer() override;
already_AddRefed<ColorLayer> CreateColorLayer() override;
already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
already_AddRefed<RefLayer> CreateRefLayer() override;
bool AreComponentAlphaLayersEnabled() override;
bool BlendingRequiresIntermediateSurface() override;
// HostLayerManager methods
void ForcePresent() override;
TextureFactoryIdentifier GetTextureFactoryIdentifier() override;
LayersBackend GetBackendType() override;
void AddInvalidRegion(const nsIntRegion& aRegion) override;
void EndTransaction(const TimeStamp& aTimeStamp,
EndTransactionFlags aFlags) override;
void EndTransaction(DrawPaintedLayerCallback aCallback, void* aCallbackData,
EndTransactionFlags aFlags) override;
Compositor* GetCompositor() const override { return nullptr; }
bool IsCompositingToScreen() const override;
TextureSourceProvider* GetTextureSourceProvider() const override;
void ClearCachedResources(Layer* aSubtree = nullptr) override;
void NotifyShadowTreeTransaction() override;
void UpdateRenderBounds(const gfx::IntRect& aRect) override;
void InvalidateAll() override {
AddInvalidRegion(nsIntRegion(mRenderBounds));
}
LayerManagerMLGPU* AsLayerManagerMLGPU() override { return this; }
const char* Name() const override { return ""; }
// This should only be called while a FrameBuilder is live.
FrameBuilder* GetCurrentFrame() const {
MOZ_ASSERT(mCurrentFrame);
return mCurrentFrame;
}
MLGDevice* GetDevice() { return mDevice; }
TimeStamp GetLastCompositionEndTime() const {
return mLastCompositionEndTime;
}
const nsIntRegion& GetRegionToClear() const { return mRegionToClear; }
uint32_t GetDebugFrameNumber() const { return mDebugFrameNumber; }
private:
void Composite();
void ComputeInvalidRegion();
void RenderLayers();
void DrawDebugOverlay();
bool PreRender();
void PostRender();
private:
RefPtr<MLGDevice> mDevice;
RefPtr<MLGSwapChain> mSwapChain;
RefPtr<TextureSourceProviderMLGPU> mTextureSourceProvider;
RefPtr<TextRenderer> mTextRenderer;
widget::CompositorWidget* mWidget;
UniquePtr<LayerProperties> mClonedLayerTreeProperties;
nsIntRegion mNextFrameInvalidRegion;
gfx::IntRect mRenderBounds;
// These are per-frame only.
bool mDrawDiagnostics;
bool mUsingInvalidation;
nsIntRegion mInvalidRegion;
Maybe<widget::WidgetRenderingContext> mWidgetContext;
IntSize mWindowSize;
TimeStamp mCompositionStartTime;
TimeStamp mLastCompositionEndTime;
RefPtr<DrawTarget> mTarget;
gfx::IntRect mTargetRect;
FrameBuilder* mCurrentFrame;
// The debug frame number is incremented every frame and is included in the
// WorldConstants bound to vertex shaders. This allows us to correlate
// a frame in RenderDoc to spew in the console.
uint32_t mDebugFrameNumber;
RefPtr<MLGBuffer> mDiagnosticVertices;
// Screenshotting for the profiler.
MLGPUScreenshotGrabber mProfilerScreenshotGrabber;
};
} // namespace layers
} // namespace mozilla
#endif

View File

@ -1,348 +0,0 @@
/* -*- 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 "MLGDevice.h"
#include "mozilla/layers/TextureHost.h"
#include "BufferCache.h"
#include "ClearRegionHelper.h"
#include "gfxConfig.h"
#include "mozilla/StaticPrefs_layers.h"
#include "gfxUtils.h"
#include "ShaderDefinitionsMLGPU.h"
#include "SharedBufferMLGPU.h"
#include "UtilityMLGPU.h"
namespace mozilla {
namespace layers {
using namespace gfx;
using namespace mlg;
MLGRenderTarget::MLGRenderTarget(MLGRenderTargetFlags aFlags)
: mFlags(aFlags), mLastDepthStart(-1) {}
MLGSwapChain::MLGSwapChain() : mIsDoubleBuffered(false) {}
bool MLGSwapChain::ApplyNewInvalidRegion(
nsIntRegion&& aRegion, const Maybe<gfx::IntRect>& aExtraRect) {
// We clamp the invalid region to the backbuffer size, otherwise the present
// can fail.
IntRect bounds(IntPoint(0, 0), GetSize());
nsIntRegion invalid = std::move(aRegion);
invalid.AndWith(bounds);
if (invalid.IsEmpty()) {
return false;
}
if (aExtraRect) {
IntRect rect = aExtraRect.value().Intersect(bounds);
if (!rect.IsEmpty()) {
invalid.OrWith(rect);
}
}
// This area is now invalid in the back and front buffers. Note that the front
// buffer is either totally valid or totally invalid, since either the last
// paint succeeded or was thrown out due to a buffer resize. Effectively, it
// will now contain the invalid region specific to this frame.
mBackBufferInvalid.OrWith(invalid);
AL_LOG("Backbuffer invalid region: %s\n",
Stringify(mBackBufferInvalid).c_str());
if (mIsDoubleBuffered) {
mFrontBufferInvalid.OrWith(invalid);
AL_LOG("Frontbuffer invalid region: %s\n",
Stringify(mFrontBufferInvalid).c_str());
}
return true;
}
MLGDevice::MLGDevice()
: mTopology(MLGPrimitiveTopology::Unknown),
mInitialized(false),
mIsValid(false),
mCanUseClearView(false),
mCanUseConstantBufferOffsetBinding(false),
mMaxConstantBufferBindSize(0) {}
MLGDevice::~MLGDevice() = default;
bool MLGDevice::Initialize() {
if (!mMaxConstantBufferBindSize) {
return Fail("FEATURE_FAILURE_NO_MAX_CB_BIND_SIZE",
"Failed to set a max constant buffer bind size");
}
if (mMaxConstantBufferBindSize < mlg::kMaxConstantBufferSize) {
// StagingBuffer depends on this value being accurate, so for now we just
// double-check it here.
return Fail("FEATURE_FAILURE_MIN_MAX_CB_BIND_SIZE",
"Minimum constant buffer bind size not met");
}
// We allow this to be pref'd off for testing. Switching it off enables
// Direct3D 11.0/Windows 7/OpenGL-style buffer code paths.
if (!StaticPrefs::layers_mlgpu_enable_buffer_sharing_AtStartup()) {
gfxConfig::EnableFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING,
"Disabled by pref");
mCanUseConstantBufferOffsetBinding = false;
}
if (mCanUseConstantBufferOffsetBinding && !VerifyConstantBufferOffsetting()) {
gfxConfig::EnableFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING,
"Constant buffer offset binding does not work");
mCanUseConstantBufferOffsetBinding = false;
}
// We allow this to be pref'd off for testing. Disabling it turns on
// ID3D11DeviceContext1::ClearView support, which is present on
// newer Windows 8+ drivers.
if (!StaticPrefs::layers_mlgpu_enable_clear_view_AtStartup()) {
mCanUseClearView = false;
}
// When compositing normal sized layer trees, we typically have small vertex
// buffers. Empirically the vertex and pixel constant buffer sizes are
// generally under 1KB and the vertex constant buffer size is under 8KB.
static const size_t kDefaultVertexBufferSize = 4096;
static const size_t kDefaultVSConstantBufferSize =
512 * kConstantBufferElementSize;
static const size_t kDefaultPSConstantBufferSize =
256 * kConstantBufferElementSize;
// Note: we create these after we've verified all the device-specific
// properties above.
mSharedVertexBuffer =
MakeUnique<SharedVertexBuffer>(this, kDefaultVertexBufferSize);
mSharedVSBuffer =
MakeUnique<SharedConstantBuffer>(this, kDefaultVSConstantBufferSize);
mSharedPSBuffer =
MakeUnique<SharedConstantBuffer>(this, kDefaultPSConstantBufferSize);
if (!mSharedVertexBuffer->Init() || !mSharedVSBuffer->Init() ||
!mSharedPSBuffer->Init()) {
return Fail("FEATURE_FAILURE_ALLOC_SHARED_BUFFER",
"Failed to allocate a shared shader buffer");
}
if (StaticPrefs::layers_mlgpu_enable_buffer_cache_AtStartup()) {
mConstantBufferCache = MakeUnique<BufferCache>(this);
}
mInitialized = true;
mIsValid = true;
return true;
}
void MLGDevice::BeginFrame() {
mSharedVertexBuffer->Reset();
mSharedPSBuffer->Reset();
mSharedVSBuffer->Reset();
}
void MLGDevice::EndFrame() {
if (mConstantBufferCache) {
mConstantBufferCache->EndFrame();
}
}
void MLGDevice::FinishSharedBufferUse() {
mSharedVertexBuffer->PrepareForUsage();
mSharedPSBuffer->PrepareForUsage();
mSharedVSBuffer->PrepareForUsage();
}
void MLGDevice::SetTopology(MLGPrimitiveTopology aTopology) {
if (mTopology == aTopology) {
return;
}
SetPrimitiveTopology(aTopology);
mTopology = aTopology;
}
void MLGDevice::SetVertexBuffer(uint32_t aSlot,
const VertexBufferSection* aSection) {
if (!aSection->IsValid()) {
return;
}
SetVertexBuffer(aSlot, aSection->GetBuffer(), aSection->Stride(),
aSection->Offset());
}
void MLGDevice::SetPSConstantBuffer(uint32_t aSlot,
const ConstantBufferSection* aSection) {
if (!aSection->IsValid()) {
return;
}
MLGBuffer* buffer = aSection->GetBuffer();
if (aSection->HasOffset()) {
uint32_t first = aSection->Offset();
uint32_t numConstants = aSection->NumConstants();
SetPSConstantBuffer(aSlot, buffer, first, numConstants);
} else {
SetPSConstantBuffer(aSlot, buffer);
}
}
void MLGDevice::SetVSConstantBuffer(uint32_t aSlot,
const ConstantBufferSection* aSection) {
if (!aSection->IsValid()) {
return;
}
MLGBuffer* buffer = aSection->GetBuffer();
if (aSection->HasOffset()) {
uint32_t first = aSection->Offset();
uint32_t numConstants = aSection->NumConstants();
SetVSConstantBuffer(aSlot, buffer, first, numConstants);
} else {
SetVSConstantBuffer(aSlot, buffer);
}
}
void MLGDevice::SetPSTexturesYUV(uint32_t aSlot, TextureSource* aTexture) {
// Note, we don't support tiled YCbCr textures.
const int Y = 0, Cb = 1, Cr = 2;
TextureSource* textures[3] = {aTexture->GetSubSource(Y),
aTexture->GetSubSource(Cb),
aTexture->GetSubSource(Cr)};
MOZ_ASSERT(textures[0]);
MOZ_ASSERT(textures[1]);
MOZ_ASSERT(textures[2]);
SetPSTextures(0, 3, textures);
}
void MLGDevice::SetPSTexture(uint32_t aSlot, TextureSource* aSource) {
SetPSTextures(aSlot, 1, &aSource);
}
void MLGDevice::SetSamplerMode(uint32_t aIndex, gfx::SamplingFilter aFilter) {
SetSamplerMode(aIndex, FilterToSamplerMode(aFilter));
}
bool MLGDevice::Fail(const nsCString& aFailureId, const nsCString* aMessage) {
const char* message =
aMessage ? aMessage->get() : "Failed initializing MLGDeviceD3D11";
gfxWarning() << "Failure initializing MLGDeviceD3D11: " << message;
mFailureId = aFailureId;
mFailureMessage = message;
return false;
}
void MLGDevice::UnmapSharedBuffers() {
mSharedVertexBuffer->Reset();
mSharedPSBuffer->Reset();
mSharedVSBuffer->Reset();
}
RefPtr<MLGBuffer> MLGDevice::GetBufferForColorSpace(YUVColorSpace aColorSpace) {
if (mColorSpaceBuffers[aColorSpace]) {
return mColorSpaceBuffers[aColorSpace];
}
YCbCrShaderConstants buffer;
memcpy(&buffer.yuvColorMatrix,
gfxUtils::YuvToRgbMatrix4x3RowMajor(aColorSpace),
sizeof(buffer.yuvColorMatrix));
RefPtr<MLGBuffer> resource = CreateBuffer(
MLGBufferType::Constant, sizeof(buffer), MLGUsage::Immutable, &buffer);
if (!resource) {
return nullptr;
}
mColorSpaceBuffers[aColorSpace] = resource;
return resource;
}
RefPtr<MLGBuffer> MLGDevice::GetBufferForColorDepthCoefficient(
ColorDepth aColorDepth) {
if (mColorDepthBuffers[aColorDepth]) {
return mColorDepthBuffers[aColorDepth];
}
YCbCrColorDepthConstants buffer;
buffer.coefficient = gfx::RescalingFactorForColorDepth(aColorDepth);
RefPtr<MLGBuffer> resource = CreateBuffer(
MLGBufferType::Constant, sizeof(buffer), MLGUsage::Immutable, &buffer);
if (!resource) {
return nullptr;
}
mColorDepthBuffers[aColorDepth] = resource;
return resource;
}
bool MLGDevice::Synchronize() { return true; }
void MLGDevice::PrepareClearRegion(ClearRegionHelper* aOut,
nsTArray<gfx::IntRect>&& aRects,
const Maybe<int32_t>& aSortIndex) {
if (CanUseClearView() && !aSortIndex) {
aOut->mRects = std::move(aRects);
return;
}
mSharedVertexBuffer->Allocate(&aOut->mInput, aRects.Length(), sizeof(IntRect),
aRects.Elements());
ClearConstants consts(aSortIndex ? aSortIndex.value() : 1);
mSharedVSBuffer->Allocate(&aOut->mVSBuffer, consts);
}
void MLGDevice::DrawClearRegion(const ClearRegionHelper& aHelper) {
// If we've set up vertices for a shader-based clear, execute that now.
if (aHelper.mInput.IsValid()) {
SetTopology(MLGPrimitiveTopology::UnitQuad);
SetVertexShader(VertexShaderID::Clear);
SetVertexBuffer(1, &aHelper.mInput);
SetVSConstantBuffer(kClearConstantBufferSlot, &aHelper.mVSBuffer);
SetBlendState(MLGBlendState::Copy);
SetPixelShader(PixelShaderID::Clear);
DrawInstanced(4, aHelper.mInput.NumVertices(), 0, 0);
return;
}
// Otherwise, if we have a normal rect list, we wanted to use the faster
// ClearView.
if (!aHelper.mRects.IsEmpty()) {
DeviceColor color(0.0, 0.0, 0.0, 0.0);
ClearView(mCurrentRT, color, aHelper.mRects.Elements(),
aHelper.mRects.Length());
}
}
void MLGDevice::WriteAsPNG(MLGTexture* aTexture, const char* aPath) {
MLGMappedResource map;
if (!Map(aTexture, MLGMapType::READ, &map)) {
return;
}
RefPtr<DataSourceSurface> surface = Factory::CreateWrappingDataSourceSurface(
map.mData, map.mStride, aTexture->GetSize(), SurfaceFormat::B8G8R8A8);
gfxUtils::WriteAsPNG(surface, aPath);
Unmap(aTexture);
}
RefPtr<MLGTexture> MLGDevice::CopyAndCreateReadbackTexture(
MLGTexture* aTexture) {
RefPtr<MLGTexture> copy =
CreateTexture(aTexture->GetSize(), SurfaceFormat::B8G8R8A8,
MLGUsage::Staging, MLGTextureFlags::None);
if (!copy) {
return nullptr;
}
CopyTexture(copy, IntPoint(0, 0), aTexture,
IntRect(IntPoint(0, 0), aTexture->GetSize()));
return copy;
}
} // namespace layers
} // namespace mozilla

View File

@ -1,481 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_MLGDevice_h
#define mozilla_gfx_layers_mlgpu_MLGDevice_h
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/EnumeratedArray.h"
#include "mozilla/RefPtr.h" // for already_AddRefed, RefCounted
#include "mozilla/TypedEnumBits.h"
#include "mozilla/WidgetUtils.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/LayersTypes.h"
#include "ImageTypes.h"
#include "MLGDeviceTypes.h"
#include "nsISupportsImpl.h"
#include "nsString.h"
#include "nsPrintfCString.h"
namespace mozilla {
namespace widget {
class CompositorWidget;
} // namespace widget
namespace gfx {
class DrawTarget;
} // namespace gfx
namespace layers {
struct GPUStats;
class BufferCache;
class ConstantBufferSection;
class DataTextureSource;
class MLGBufferD3D11;
class MLGDeviceD3D11;
class MLGRenderTargetD3D11;
class MLGResourceD3D11;
class MLGTexture;
class MLGTextureD3D11;
class SharedVertexBuffer;
class SharedConstantBuffer;
class TextureSource;
class VertexBufferSection;
struct ClearRegionHelper;
class MLGRenderTarget {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MLGRenderTarget)
virtual gfx::IntSize GetSize() const = 0;
virtual MLGRenderTargetD3D11* AsD3D11() { return nullptr; }
// Returns the underlying texture of the render target.
virtual MLGTexture* GetTexture() = 0;
bool HasDepthBuffer() const {
return (mFlags & MLGRenderTargetFlags::ZBuffer) ==
MLGRenderTargetFlags::ZBuffer;
}
int32_t GetLastDepthStart() const { return mLastDepthStart; }
void SetLastDepthStart(int32_t aDepthStart) { mLastDepthStart = aDepthStart; }
protected:
explicit MLGRenderTarget(MLGRenderTargetFlags aFlags);
virtual ~MLGRenderTarget() = default;
protected:
MLGRenderTargetFlags mFlags;
// When using a depth buffer, callers can track the range of depth values
// that were last used.
int32_t mLastDepthStart;
};
class MLGSwapChain {
protected:
virtual ~MLGSwapChain() = default;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MLGSwapChain)
virtual RefPtr<MLGRenderTarget> AcquireBackBuffer() = 0;
virtual bool ResizeBuffers(const gfx::IntSize& aSize) = 0;
virtual gfx::IntSize GetSize() const = 0;
// Present to the screen.
virtual void Present() = 0;
// Force a present without waiting for the previous frame's present to
// complete.
virtual void ForcePresent() = 0;
// Copy an area of the backbuffer to a draw target.
virtual void CopyBackbuffer(gfx::DrawTarget* aTarget,
const gfx::IntRect& aBounds) = 0;
// Free any internal resources.
virtual void Destroy() = 0;
// Give the new invalid region to the swap chain in preparation for
// acquiring the backbuffer. If the new invalid region is empty,
// this returns false and no composite is required.
//
// The extra rect is used for the debug overlay, which is factored in
// separately to avoid causing unnecessary composites.
bool ApplyNewInvalidRegion(nsIntRegion&& aRegion,
const Maybe<gfx::IntRect>& aExtraRect);
const nsIntRegion& GetBackBufferInvalidRegion() const {
return mBackBufferInvalid;
}
protected:
MLGSwapChain();
protected:
gfx::IntSize mLastPresentSize;
// The swap chain tracks the invalid region of its buffers. After presenting,
// the invalid region for the backbuffer is cleared. If using double
// buffering, it is set to the area of the non-presented buffer that was not
// painted this frame. The initial invalid region each frame comes from
// LayerManagerMLGPU, and is combined with the back buffer's invalid region
// before frame building begins.
nsIntRegion mBackBufferInvalid;
nsIntRegion mFrontBufferInvalid;
bool mIsDoubleBuffered;
};
class MLGResource {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MLGResource)
public:
enum class Type { Buffer, Texture };
virtual Type GetType() const = 0;
virtual MLGResourceD3D11* AsResourceD3D11() { return nullptr; }
protected:
virtual ~MLGResource() = default;
};
// A buffer for use as a shader input.
class MLGBuffer : public MLGResource {
public:
Type GetType() const override { return Type::Buffer; }
virtual MLGBufferD3D11* AsD3D11() { return nullptr; }
virtual size_t GetSize() const = 0;
protected:
virtual ~MLGBuffer() = default;
};
// This is a lower-level resource than a TextureSource. It wraps
// a 2D texture.
class MLGTexture : public MLGResource {
public:
Type GetType() const override { return Type::Texture; }
virtual MLGTextureD3D11* AsD3D11() { return nullptr; }
const gfx::IntSize& GetSize() const { return mSize; }
protected:
gfx::IntSize mSize;
};
enum class VertexShaderID {
TexturedQuad,
TexturedVertex,
ColoredQuad,
ColoredVertex,
BlendVertex,
Clear,
MaskCombiner,
DiagnosticText,
MaxShaders
};
enum class PixelShaderID {
ColoredQuad,
ColoredVertex,
TexturedQuadRGB,
TexturedQuadRGBA,
TexturedVertexRGB,
TexturedVertexRGBA,
TexturedQuadIMC4,
TexturedQuadIdentityIMC4,
TexturedQuadNV12,
TexturedVertexIMC4,
TexturedVertexIdentityIMC4,
TexturedVertexNV12,
ComponentAlphaQuad,
ComponentAlphaVertex,
BlendMultiply,
BlendScreen,
BlendOverlay,
BlendDarken,
BlendLighten,
BlendColorDodge,
BlendColorBurn,
BlendHardLight,
BlendSoftLight,
BlendDifference,
BlendExclusion,
BlendHue,
BlendSaturation,
BlendColor,
BlendLuminosity,
Clear,
MaskCombiner,
DiagnosticText,
MaxShaders
};
class MLGDevice {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MLGDevice)
MLGDevice();
virtual bool Initialize();
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier(
widget::CompositorWidget* aWidget) const = 0;
virtual int32_t GetMaxTextureSize() const = 0;
virtual LayersBackend GetLayersBackend() const = 0;
virtual RefPtr<MLGSwapChain> CreateSwapChainForWidget(
widget::CompositorWidget* aWidget) = 0;
// Markers for when we start and finish issuing "normal" (i.e., non-
// diagnostic) draw commands for the frame.
virtual void StartDiagnostics(uint32_t aInvalidPixels) = 0;
virtual void EndDiagnostics() = 0;
virtual void GetDiagnostics(GPUStats* aStats) = 0;
// Layers interaction.
virtual RefPtr<DataTextureSource> CreateDataTextureSource(
TextureFlags aFlags) = 0;
// Resource access
virtual bool Map(MLGResource* aResource, MLGMapType aType,
MLGMappedResource* aMap) = 0;
virtual void Unmap(MLGResource* aResource) = 0;
virtual void UpdatePartialResource(MLGResource* aResource,
const gfx::IntRect* aRect, void* aData,
uint32_t aStride) = 0;
virtual void CopyTexture(MLGTexture* aDest, const gfx::IntPoint& aTarget,
MLGTexture* aSource, const gfx::IntRect& aRect) = 0;
// Begin a frame. This clears and resets all shared buffers.
virtual void BeginFrame();
virtual void EndFrame();
// State setup commands.
virtual void SetRenderTarget(MLGRenderTarget* aRT) = 0;
virtual MLGRenderTarget* GetRenderTarget() = 0;
virtual void SetViewport(const gfx::IntRect& aRT) = 0;
virtual void SetScissorRect(const Maybe<gfx::IntRect>& aScissorRect) = 0;
virtual void SetVertexShader(VertexShaderID aVertexShader) = 0;
virtual void SetPixelShader(PixelShaderID aPixelShader) = 0;
virtual void SetSamplerMode(uint32_t aIndex, SamplerMode aSamplerMode) = 0;
virtual void SetBlendState(MLGBlendState aBlendState) = 0;
virtual void SetVertexBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
uint32_t aStride, uint32_t aOffset = 0) = 0;
virtual void SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) = 0;
virtual void SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) = 0;
virtual void SetPSTextures(uint32_t aSlot, uint32_t aNumTextures,
TextureSource* const* aTextures) = 0;
virtual void SetPSTexture(uint32_t aSlot, MLGTexture* aTexture) = 0;
virtual void SetDepthTestMode(MLGDepthTestMode aMode) = 0;
// If supported, bind constant buffers at a particular offset. These can only
// be used if CanUseConstantBufferOffsetBinding returns true.
virtual void SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
uint32_t aFirstConstant,
uint32_t aNumConstants) = 0;
virtual void SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
uint32_t aFirstConstant,
uint32_t aNumConstants) = 0;
// Set the topology. No API call is made if the topology has not changed.
// The UnitQuad topology implicity binds a unit quad triangle strip as
// vertex buffer #0.
void SetTopology(MLGPrimitiveTopology aTopology);
// Set textures that have special binding logic, and bind to multiple slots.
virtual void SetPSTexturesNV12(uint32_t aSlot, TextureSource* aTexture) = 0;
void SetPSTexturesYUV(uint32_t aSlot, TextureSource* aTexture);
virtual RefPtr<MLGBuffer> CreateBuffer(
MLGBufferType aType, uint32_t aSize, MLGUsage aUsage,
const void* aInitialData = nullptr) = 0;
virtual RefPtr<MLGTexture> CreateTexture(const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat,
MLGUsage aUsage,
MLGTextureFlags aFlags) = 0;
// Unwrap the underlying GPU texture in the given TextureSource, and re-wrap
// it in an MLGTexture structure.
virtual RefPtr<MLGTexture> CreateTexture(TextureSource* aSource) = 0;
virtual RefPtr<MLGRenderTarget> CreateRenderTarget(
const gfx::IntSize& aSize,
MLGRenderTargetFlags aFlags = MLGRenderTargetFlags::Default) = 0;
// Clear a render target to the given color, or clear a depth buffer.
virtual void Clear(MLGRenderTarget* aRT, const gfx::DeviceColor& aColor) = 0;
virtual void ClearDepthBuffer(MLGRenderTarget* aRT) = 0;
// This is only available if CanUseClearView() returns true.
virtual void ClearView(MLGRenderTarget* aRT, const gfx::DeviceColor& aColor,
const gfx::IntRect* aRects, size_t aNumRects) = 0;
// Drawing Commands
virtual void Draw(uint32_t aVertexCount, uint32_t aOffset) = 0;
virtual void DrawInstanced(uint32_t aVertexCountPerInstance,
uint32_t aInstanceCount, uint32_t aVertexOffset,
uint32_t aInstanceOffset) = 0;
virtual void Flush() = 0;
// This unlocks any textures that were implicitly locked during drawing.
virtual void UnlockAllTextures() = 0;
virtual MLGDeviceD3D11* AsD3D11() { return nullptr; }
// Helpers.
void SetVertexBuffer(uint32_t aSlot, const VertexBufferSection* aSection);
void SetPSConstantBuffer(uint32_t aSlot,
const ConstantBufferSection* aSection);
void SetVSConstantBuffer(uint32_t aSlot,
const ConstantBufferSection* aSection);
void SetPSTexture(uint32_t aSlot, TextureSource* aSource);
void SetSamplerMode(uint32_t aIndex, gfx::SamplingFilter aFilter);
// This creates or returns a previously created constant buffer, containing
// a YCbCrShaderConstants instance.
RefPtr<MLGBuffer> GetBufferForColorSpace(gfx::YUVColorSpace aColorSpace);
// This creates or returns a previously created constant buffer, containing
// a YCbCrBitDepthConstants instance.
RefPtr<MLGBuffer> GetBufferForColorDepthCoefficient(
gfx::ColorDepth aColorDepth);
// A shared buffer that can be used to build VertexBufferSections.
SharedVertexBuffer* GetSharedVertexBuffer() {
return mSharedVertexBuffer.get();
}
// A shared buffer that can be used to build ConstantBufferSections. Intended
// to be used with vertex shaders.
SharedConstantBuffer* GetSharedVSBuffer() { return mSharedVSBuffer.get(); }
// A shared buffer that can be used to build ConstantBufferSections. Intended
// to be used with pixel shaders.
SharedConstantBuffer* GetSharedPSBuffer() { return mSharedPSBuffer.get(); }
// A cache for constant buffers, used when offset-based binding is not
// supported.
BufferCache* GetConstantBufferCache() { return mConstantBufferCache.get(); }
// Unmap and upload all shared buffers to the GPU.
void FinishSharedBufferUse();
// These are used to detect and report initialization failure.
virtual bool IsValid() const { return mInitialized && mIsValid; }
const nsCString& GetFailureId() const { return mFailureId; }
const nsCString& GetFailureMessage() const { return mFailureMessage; }
// Prepare a clear-region operation to be run at a later time.
void PrepareClearRegion(ClearRegionHelper* aOut,
nsTArray<gfx::IntRect>&& aRects,
const Maybe<int32_t>& aSortIndex);
// Execute a clear-region operation. This may change shader state.
void DrawClearRegion(const ClearRegionHelper& aHelper);
// If supported, synchronize with the SyncObject given to clients.
virtual bool Synchronize();
// If this returns true, ClearView() can be called.
bool CanUseClearView() const { return mCanUseClearView; }
// If this returns true, constant buffers can be bound at specific offsets for
// a given run of bytes. This is only supported on Windows 8+ for Direct3D 11.
bool CanUseConstantBufferOffsetBinding() const {
return mCanUseConstantBufferOffsetBinding;
}
// Return the maximum number of elements that can be bound to a constant
// buffer. This is different than the maximum size of a buffer (there is
// no such limit on Direct3D 11.1).
//
// The return value must be a power of two.
size_t GetMaxConstantBufferBindSize() const {
return mMaxConstantBufferBindSize;
}
// Helper function for unbinding textures since SetPSTexture is overloaded.
void UnsetPSTexture(uint32_t aSlot) {
TextureSource* nullTexture = nullptr;
SetPSTexture(aSlot, nullTexture);
}
// Debugging helper function for dumping an MLGTexture to a file.
void WriteAsPNG(MLGTexture* aTexture, const char* aPath);
// Debugging helper function for copying a texture for later dumping to a
// file.
RefPtr<MLGTexture> CopyAndCreateReadbackTexture(MLGTexture* aTexture);
protected:
virtual ~MLGDevice();
virtual void SetPrimitiveTopology(MLGPrimitiveTopology aTopology) = 0;
// Optionally run a runtime test to determine if constant buffer offset
// binding works.
virtual bool VerifyConstantBufferOffsetting() { return true; }
// Used during initialization to record failure reasons.
bool Fail(const nsCString& aFailureId, const nsCString* aMessage);
// Used during initialization to record failure reasons. Note: our
// MOZ_FORMAT_PRINTF macro does not work on this function, so we
// disable the warning.
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-security"
#endif
template <typename... T>
bool Fail(const char* aFailureId) {
nsCString failureId(aFailureId);
return Fail(failureId, nullptr);
}
template <typename... T>
bool Fail(const char* aFailureId, const char* aMessage, const T&... args) {
nsCString failureId(aFailureId);
nsPrintfCString message(aMessage, args...);
return Fail(failureId, &message);
}
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
void UnmapSharedBuffers();
private:
MLGPrimitiveTopology mTopology;
UniquePtr<SharedVertexBuffer> mSharedVertexBuffer;
UniquePtr<SharedConstantBuffer> mSharedVSBuffer;
UniquePtr<SharedConstantBuffer> mSharedPSBuffer;
UniquePtr<BufferCache> mConstantBufferCache;
nsCString mFailureId;
nsCString mFailureMessage;
bool mInitialized;
typedef EnumeratedArray<gfx::YUVColorSpace, gfx::YUVColorSpace::UNKNOWN,
RefPtr<MLGBuffer>>
ColorSpaceArray;
ColorSpaceArray mColorSpaceBuffers;
typedef EnumeratedArray<gfx::ColorDepth, gfx::ColorDepth::UNKNOWN,
RefPtr<MLGBuffer>>
ColorDepthArray;
ColorDepthArray mColorDepthBuffers;
protected:
bool mIsValid;
bool mCanUseClearView;
bool mCanUseConstantBufferOffsetBinding;
size_t mMaxConstantBufferBindSize;
RefPtr<MLGRenderTarget> mCurrentRT;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_MLGDevice_h

View File

@ -1,102 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_MLGDeviceTypes_h
#define mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
#include "mozilla/TypedEnumBits.h"
#include "mozilla/gfx/Types.h"
namespace mozilla {
namespace layers {
enum class MLGUsage {
// GPU read-only, CPU write once on creation and read/write never.
Immutable,
// GPU read-only, CPU write-only. Must be mapped with WRITE_DISCARD.
Dynamic,
// GPU read/write-only, no CPU access.
Default,
// GPU->CPU transfer, and read from the CPU.
Staging
};
enum class MLGDepthTestMode {
Disabled,
Write,
ReadOnly,
AlwaysWrite,
MaxModes
};
enum class MLGBufferType : uint32_t { Vertex, Constant };
enum class SamplerMode {
// Linear filter, clamped to border.
LinearClamp = 0,
// Linear filter, clamped to transparent pixels.
LinearClampToZero,
// Linear filter, wrap edges.
LinearRepeat,
// Point filter, clamped to border.
Point,
MaxModes
};
enum class MLGBlendState {
Copy = 0,
Over,
OverAndPremultiply,
Min,
ComponentAlpha,
MaxStates
};
enum class MLGPrimitiveTopology {
Unknown = 0,
TriangleStrip = 1,
TriangleList = 2,
UnitQuad = 3,
UnitTriangle = 4
};
struct MLGMappedResource {
uint8_t* mData;
uint32_t mStride;
};
enum class MLGMapType { READ = 0, WRITE, READ_WRITE, WRITE_DISCARD };
enum class MLGTextureFlags { None, ShaderResource, RenderTarget };
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MLGTextureFlags);
enum class MLGRenderTargetFlags : uint32_t { Default = 0, ZBuffer = (1 << 0) };
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MLGRenderTargetFlags);
// NVIDIA drivers crash when we supply too many rects to ClearView - it
// seems to cause a stack overflow >= 20 rects. We cap to 12 for now.
static const size_t kMaxClearViewRects = 12;
static inline SamplerMode FilterToSamplerMode(gfx::SamplingFilter aFilter) {
switch (aFilter) {
case gfx::SamplingFilter::POINT:
return SamplerMode::Point;
case gfx::SamplingFilter::LINEAR:
case gfx::SamplingFilter::GOOD:
return SamplerMode::LinearClamp;
default:
MOZ_ASSERT_UNREACHABLE("Unknown sampler mode");
return SamplerMode::LinearClamp;
}
}
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h

View File

@ -1,336 +0,0 @@
/* -*- 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 "MLGPUScreenshotGrabber.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/layers/ProfilerScreenshots.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Swizzle.h"
#include "mozilla/ProfilerMarkers.h"
#include "SharedBufferMLGPU.h"
#include "ShaderDefinitionsMLGPU.h"
#include "nsTArray.h"
namespace mozilla {
using namespace gfx;
namespace layers {
using namespace mlg;
/**
* The actual implementation of screenshot grabbing.
* The MLGPUScreenshotGrabberImpl object is destroyed if the profiler is
* disabled and MaybeGrabScreenshot notices it.
*/
class MLGPUScreenshotGrabberImpl final {
public:
explicit MLGPUScreenshotGrabberImpl(const IntSize& aReadbackTextureSize);
~MLGPUScreenshotGrabberImpl();
void GrabScreenshot(MLGDevice* aDevice, MLGTexture* aTexture);
void ProcessQueue();
private:
struct QueueItem final {
mozilla::TimeStamp mTimeStamp;
RefPtr<MLGTexture> mScreenshotReadbackTexture;
gfx::IntSize mScreenshotSize;
gfx::IntSize mWindowSize;
RefPtr<MLGDevice> mDevice;
uintptr_t mWindowIdentifier;
};
RefPtr<MLGTexture> ScaleDownWindowTargetToSize(MLGDevice* aCompositor,
const gfx::IntSize& aDestSize,
MLGTexture* aWindowTarget,
size_t aLevel);
struct CachedLevel {
RefPtr<MLGRenderTarget> mRenderTarget;
RefPtr<MLGBuffer> mVertexBuffer;
RefPtr<MLGBuffer> mWorldConstants;
};
bool BlitTexture(MLGDevice* aDevice, CachedLevel& aDest, MLGTexture* aSource,
const IntSize& aSourceSize, const IntSize& aDestSize);
already_AddRefed<MLGTexture> TakeNextReadbackTexture(MLGDevice* aCompositor);
void ReturnReadbackTexture(MLGTexture* aReadbackTexture);
nsTArray<CachedLevel> mCachedLevels;
nsTArray<RefPtr<MLGTexture>> mAvailableReadbackTextures;
Maybe<QueueItem> mCurrentFrameQueueItem;
nsTArray<QueueItem> mQueue;
RefPtr<ProfilerScreenshots> mProfilerScreenshots;
const IntSize mReadbackTextureSize;
};
MLGPUScreenshotGrabber::MLGPUScreenshotGrabber() = default;
MLGPUScreenshotGrabber::~MLGPUScreenshotGrabber() = default;
void MLGPUScreenshotGrabber::MaybeGrabScreenshot(MLGDevice* aDevice,
MLGTexture* aTexture) {
if (ProfilerScreenshots::IsEnabled()) {
if (!mImpl) {
mImpl = MakeUnique<MLGPUScreenshotGrabberImpl>(
ProfilerScreenshots::ScreenshotSize());
}
mImpl->GrabScreenshot(aDevice, aTexture);
} else if (mImpl) {
Destroy();
}
}
void MLGPUScreenshotGrabber::MaybeProcessQueue() {
if (ProfilerScreenshots::IsEnabled()) {
if (!mImpl) {
mImpl = MakeUnique<MLGPUScreenshotGrabberImpl>(
ProfilerScreenshots::ScreenshotSize());
}
mImpl->ProcessQueue();
} else if (mImpl) {
Destroy();
}
}
void MLGPUScreenshotGrabber::NotifyEmptyFrame() {
#ifdef MOZ_GECKO_PROFILER
PROFILER_MARKER_UNTYPED("NoCompositorScreenshot because nothing changed",
GRAPHICS);
#endif
}
void MLGPUScreenshotGrabber::Destroy() { mImpl = nullptr; }
MLGPUScreenshotGrabberImpl::MLGPUScreenshotGrabberImpl(
const IntSize& aReadbackTextureSize)
: mReadbackTextureSize(aReadbackTextureSize) {}
MLGPUScreenshotGrabberImpl::~MLGPUScreenshotGrabberImpl() {
// Any queue items in mQueue or mCurrentFrameQueueItem will be lost.
// That's ok: Either the profiler has stopped and we don't care about these
// screenshots, or the window is closing and we don't really need the last
// few frames from the window.
}
// Scale down aWindowTexture into a MLGTexture of size
// mReadbackTextureSize * (1 << aLevel) and return that MLGTexture.
// Don't scale down by more than a factor of 2 with a single scaling operation,
// because it'll look bad. If higher scales are needed, use another
// intermediate target by calling this function recursively with aLevel + 1.
RefPtr<MLGTexture> MLGPUScreenshotGrabberImpl::ScaleDownWindowTargetToSize(
MLGDevice* aDevice, const IntSize& aDestSize, MLGTexture* aWindowTexture,
size_t aLevel) {
aDevice->SetScissorRect(Nothing());
aDevice->SetDepthTestMode(MLGDepthTestMode::Disabled);
aDevice->SetTopology(MLGPrimitiveTopology::UnitQuad);
// DiagnosticText happens to be the simplest shader we have to draw a quad.
aDevice->SetVertexShader(VertexShaderID::DiagnosticText);
aDevice->SetPixelShader(PixelShaderID::DiagnosticText);
aDevice->SetBlendState(MLGBlendState::Copy);
aDevice->SetSamplerMode(0, SamplerMode::LinearClamp);
if (aLevel == mCachedLevels.Length()) {
RefPtr<MLGRenderTarget> rt =
aDevice->CreateRenderTarget(mReadbackTextureSize * (1 << aLevel));
mCachedLevels.AppendElement(CachedLevel{rt, nullptr, nullptr});
}
MOZ_RELEASE_ASSERT(aLevel < mCachedLevels.Length());
RefPtr<MLGTexture> sourceTarget = aWindowTexture;
IntSize sourceSize = aWindowTexture->GetSize();
if (aWindowTexture->GetSize().width > aDestSize.width * 2) {
sourceSize = aDestSize * 2;
sourceTarget = ScaleDownWindowTargetToSize(aDevice, sourceSize,
aWindowTexture, aLevel + 1);
}
if (sourceTarget) {
if (BlitTexture(aDevice, mCachedLevels[aLevel], sourceTarget, sourceSize,
aDestSize)) {
return mCachedLevels[aLevel].mRenderTarget->GetTexture();
}
}
return nullptr;
}
bool MLGPUScreenshotGrabberImpl::BlitTexture(MLGDevice* aDevice,
CachedLevel& aLevel,
MLGTexture* aSource,
const IntSize& aSourceSize,
const IntSize& aDestSize) {
MOZ_ASSERT(aLevel.mRenderTarget);
MLGRenderTarget* rt = aLevel.mRenderTarget;
MOZ_ASSERT(aDestSize <= rt->GetSize());
struct TextureRect {
Rect bounds;
Rect texCoords;
};
if (!aLevel.mVertexBuffer) {
TextureRect rect;
rect.bounds = Rect(Point(), Size(aDestSize));
rect.texCoords =
Rect(0.0, 0.0, Float(aSourceSize.width) / aSource->GetSize().width,
Float(aSourceSize.height) / aSource->GetSize().height);
VertexStagingBuffer instances;
if (!instances.AppendItem(rect)) {
return false;
}
RefPtr<MLGBuffer> vertices = aDevice->CreateBuffer(
MLGBufferType::Vertex, instances.NumItems() * instances.SizeOfItem(),
MLGUsage::Immutable, instances.GetBufferStart());
if (!vertices) {
return false;
}
aLevel.mVertexBuffer = vertices;
}
if (!aLevel.mWorldConstants) {
WorldConstants vsConstants;
Matrix4x4 projection = Matrix4x4::Translation(-1.0, 1.0, 0.0);
projection.PreScale(2.0 / float(rt->GetSize().width),
2.0 / float(rt->GetSize().height), 1.0f);
projection.PreScale(1.0f, -1.0f, 1.0f);
memcpy(vsConstants.projection, &projection._11, 64);
vsConstants.targetOffset = Point();
vsConstants.sortIndexOffset = 0;
vsConstants.debugFrameNumber = 0;
aLevel.mWorldConstants =
aDevice->CreateBuffer(MLGBufferType::Constant, sizeof(vsConstants),
MLGUsage::Immutable, &vsConstants);
if (!aLevel.mWorldConstants) {
return false;
}
}
aDevice->SetRenderTarget(rt);
aDevice->SetPSTexture(0, aSource);
aDevice->SetViewport(IntRect(IntPoint(0, 0), rt->GetSize()));
aDevice->SetVertexBuffer(1, aLevel.mVertexBuffer, sizeof(TextureRect));
aDevice->SetVSConstantBuffer(kWorldConstantBufferSlot,
aLevel.mWorldConstants);
aDevice->DrawInstanced(4, 1, 0, 0);
return true;
}
void MLGPUScreenshotGrabberImpl::GrabScreenshot(MLGDevice* aDevice,
MLGTexture* aTexture) {
Size windowSize(aTexture->GetSize());
float scale = std::min(mReadbackTextureSize.width / windowSize.width,
mReadbackTextureSize.height / windowSize.height);
IntSize scaledSize = IntSize::Round(windowSize * scale);
// The initial target is non-GPU readable. This copy could probably be
// avoided if we had created the swap chain differently. However we
// don't know if that may inadvertently affect performance in the
// non-profiling case.
RefPtr<MLGTexture> windowTexture = aDevice->CreateTexture(
aTexture->GetSize(), SurfaceFormat::B8G8R8A8, MLGUsage::Default,
MLGTextureFlags::ShaderResource);
aDevice->CopyTexture(windowTexture, IntPoint(), aTexture,
IntRect(IntPoint(), aTexture->GetSize()));
RefPtr<MLGTexture> scaledTarget =
ScaleDownWindowTargetToSize(aDevice, scaledSize, windowTexture, 0);
if (!scaledTarget) {
PROFILER_MARKER_UNTYPED(
"NoCompositorScreenshot because ScaleDownWindowTargetToSize failed",
GRAPHICS);
return;
}
RefPtr<MLGTexture> readbackTexture = TakeNextReadbackTexture(aDevice);
if (!readbackTexture) {
PROFILER_MARKER_UNTYPED(
"NoCompositorScreenshot because AsyncReadbackReadbackTexture creation "
"failed",
GRAPHICS);
return;
}
aDevice->CopyTexture(readbackTexture, IntPoint(), scaledTarget,
IntRect(IntPoint(), mReadbackTextureSize));
// This QueueItem will be added to the queue at the end of the next call to
// ProcessQueue(). This ensures that the ReadbackTexture isn't mapped into
// main memory until the next frame. If we did it in this frame, we'd block on
// the GPU.
mCurrentFrameQueueItem =
Some(QueueItem{TimeStamp::Now(), std::move(readbackTexture), scaledSize,
aTexture->GetSize(), aDevice,
reinterpret_cast<uintptr_t>(static_cast<void*>(this))});
}
already_AddRefed<MLGTexture>
MLGPUScreenshotGrabberImpl::TakeNextReadbackTexture(MLGDevice* aDevice) {
if (!mAvailableReadbackTextures.IsEmpty()) {
RefPtr<MLGTexture> readbackTexture = mAvailableReadbackTextures[0];
mAvailableReadbackTextures.RemoveElementAt(0);
return readbackTexture.forget();
}
return aDevice
->CreateTexture(mReadbackTextureSize, SurfaceFormat::B8G8R8A8,
MLGUsage::Staging, MLGTextureFlags::None)
.forget();
}
void MLGPUScreenshotGrabberImpl::ReturnReadbackTexture(
MLGTexture* aReadbackTexture) {
mAvailableReadbackTextures.AppendElement(aReadbackTexture);
}
void MLGPUScreenshotGrabberImpl::ProcessQueue() {
if (!mQueue.IsEmpty()) {
if (!mProfilerScreenshots) {
mProfilerScreenshots = new ProfilerScreenshots();
}
for (const auto& item : mQueue) {
mProfilerScreenshots->SubmitScreenshot(
item.mWindowIdentifier, item.mWindowSize, item.mScreenshotSize,
item.mTimeStamp, [&item](DataSourceSurface* aTargetSurface) {
MLGMappedResource map;
if (!item.mDevice->Map(item.mScreenshotReadbackTexture,
MLGMapType::READ, &map)) {
return false;
}
DataSourceSurface::ScopedMap destMap(aTargetSurface,
DataSourceSurface::WRITE);
bool result =
SwizzleData(map.mData, map.mStride, SurfaceFormat::B8G8R8A8,
destMap.GetData(), destMap.GetStride(),
aTargetSurface->GetFormat(), item.mScreenshotSize);
item.mDevice->Unmap(item.mScreenshotReadbackTexture);
return result;
});
ReturnReadbackTexture(item.mScreenshotReadbackTexture);
}
}
mQueue.Clear();
if (mCurrentFrameQueueItem) {
mQueue.AppendElement(std::move(*mCurrentFrameQueueItem));
mCurrentFrameQueueItem = Nothing();
}
}
} // namespace layers
} // namespace mozilla

View File

@ -1,59 +0,0 @@
/* -*- 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_MLGPUScreenshotGrabber_h
#define mozilla_layers_MLGPUScreenshotGrabber_h
#include "mozilla/UniquePtr.h"
#include "mozilla/layers/MLGDevice.h"
namespace mozilla {
namespace layers {
class MLGPUScreenshotGrabberImpl;
/**
* Used by LayerManagerComposite to grab snapshots from the compositor and
* submit them to the Gecko profiler.
* Doesn't do any work if the profiler is not running or the "screenshots"
* feature is not enabled.
* Screenshots are scaled down to fit within a fixed size, and read back to
* main memory using async readback. Scaling is done in multiple scale-by-0.5x
* steps using CompositingRenderTargets and Compositor::BlitFromRenderTarget,
* and readback is done using AsyncReadbackBuffers.
*/
class MLGPUScreenshotGrabber final {
public:
MLGPUScreenshotGrabber();
~MLGPUScreenshotGrabber();
// Scale the contents of aTexture into an appropriately sized MLGTexture
// and read its contents into an AsyncReadbackBuffer. The AsyncReadbackBuffer
// is not mapped into main memory until the second call to
// MaybeProcessQueue() after this call to MaybeGrabScreenshot().
void MaybeGrabScreenshot(MLGDevice* aDevice, MLGTexture* aTexture);
// Map the contents of any outstanding AsyncReadbackBuffers from previous
// composites into main memory and submit each screenshot to the profiler.
void MaybeProcessQueue();
// Insert a special profiler marker for a composite that didn't do any actual
// compositing, so that the profiler knows why no screenshot was taken for
// this frame.
void NotifyEmptyFrame();
// Destroy all Compositor-related resources that this class is holding on to.
void Destroy();
private:
// non-null while ProfilerScreenshots::IsEnabled() returns true
UniquePtr<MLGPUScreenshotGrabberImpl> mImpl;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_MLGPUScreenshotGrabber_h

View File

@ -1,173 +0,0 @@
/* -*- 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 "MaskOperation.h"
#include "FrameBuilder.h"
#include "LayerMLGPU.h"
#include "mozilla/layers/LayersHelpers.h"
#include "MLGDevice.h"
#include "TexturedLayerMLGPU.h"
namespace mozilla {
namespace layers {
using namespace gfx;
MaskOperation::MaskOperation(FrameBuilder* aBuilder) {}
MaskOperation::MaskOperation(FrameBuilder* aBuilder, MLGTexture* aSource)
: mTexture(aSource) {}
MaskOperation::~MaskOperation() = default;
static gfx::Rect ComputeQuadForMaskLayer(Layer* aLayer, const IntSize& aSize) {
const Matrix4x4& transform = aLayer->GetEffectiveTransform();
MOZ_ASSERT(transform.Is2D(), "Mask layers should not have 3d transforms");
Rect bounds(Point(0, 0), Size(aSize));
return transform.As2D().TransformBounds(bounds);
}
Rect MaskOperation::ComputeMaskRect(Layer* aLayer) const {
Layer* maskLayer = aLayer->GetMaskLayer() ? aLayer->GetMaskLayer()
: aLayer->GetAncestorMaskLayerAt(0);
MOZ_ASSERT(
(aLayer->GetAncestorMaskLayerCount() == 0 && aLayer->GetMaskLayer()) ||
(aLayer->GetAncestorMaskLayerCount() == 1 && !aLayer->GetMaskLayer()));
return ComputeQuadForMaskLayer(maskLayer, mTexture->GetSize());
}
// This is only needed for std::map.
bool MaskTexture::operator<(const MaskTexture& aOther) const {
if (mRect.X() != aOther.mRect.X()) {
return mRect.X() < aOther.mRect.X();
}
if (mRect.Y() != aOther.mRect.Y()) {
return mRect.Y() < aOther.mRect.Y();
}
if (mRect.Width() != aOther.mRect.Width()) {
return mRect.Width() < aOther.mRect.Width();
}
if (mRect.Height() != aOther.mRect.Height()) {
return mRect.Height() < aOther.mRect.Height();
}
return mSource < aOther.mSource;
}
RefPtr<TextureSource> GetMaskLayerTexture(Layer* aLayer) {
LayerMLGPU* layer = aLayer->AsHostLayer()->AsLayerMLGPU();
TexturedLayerMLGPU* texLayer = layer->AsTexturedLayerMLGPU();
if (!texLayer) {
MOZ_ASSERT_UNREACHABLE("Mask layers should be texture layers");
return nullptr;
}
RefPtr<TextureSource> source = texLayer->BindAndGetTexture();
if (!source) {
gfxWarning() << "Mask layer does not have a TextureSource";
return nullptr;
}
return source;
}
MaskCombineOperation::MaskCombineOperation(FrameBuilder* aBuilder)
: MaskOperation(aBuilder), mBuilder(aBuilder) {}
MaskCombineOperation::~MaskCombineOperation() = default;
void MaskCombineOperation::Init(const MaskTextureList& aTextures) {
// All masks for a single layer exist in the same coordinate space. Find the
// area that covers all rects.
Rect area = aTextures[0].mRect;
for (size_t i = 1; i < aTextures.size(); i++) {
area = area.Intersect(aTextures[i].mRect);
}
// Go through and decide which areas of the textures are relevant.
for (size_t i = 0; i < aTextures.size(); i++) {
Rect rect = aTextures[i].mRect.Intersect(area);
if (rect.IsEmpty()) {
continue;
}
rect -= aTextures[i].mRect.TopLeft();
mTextures.push_back(MaskTexture(rect, aTextures[i].mSource));
}
IntRect size;
Rect bounds = area;
bounds.RoundOut();
bounds.ToIntRect(&size);
if (size.IsEmpty()) {
return;
}
mTarget = mBuilder->GetDevice()->CreateRenderTarget(size.Size());
if (mTarget) {
mTexture = mTarget->GetTexture();
}
mArea = area;
}
void MaskCombineOperation::PrepareForRendering() {
for (const auto& entry : mTextures) {
Rect texCoords = TextureRectToCoords(entry.mRect, entry.mSource->GetSize());
SharedVertexBuffer* shared = mBuilder->GetDevice()->GetSharedVertexBuffer();
VertexBufferSection section;
if (!shared->Allocate(&section, 1, sizeof(texCoords), &texCoords)) {
continue;
}
mInputBuffers.push_back(section);
}
}
void MaskCombineOperation::Render() {
if (!mTarget) {
return;
}
RefPtr<MLGDevice> device = mBuilder->GetDevice();
device->SetTopology(MLGPrimitiveTopology::UnitQuad);
device->SetVertexShader(VertexShaderID::MaskCombiner);
device->SetPixelShader(PixelShaderID::MaskCombiner);
device->SetSamplerMode(0, SamplerMode::LinearClamp);
device->SetBlendState(MLGBlendState::Min);
// Since the mask operation is effectively an AND operation, we initialize
// the entire r-channel to 1.
device->Clear(mTarget, DeviceColor(1, 0, 0, 1));
device->SetScissorRect(Nothing());
device->SetRenderTarget(mTarget);
device->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
for (size_t i = 0; i < mInputBuffers.size(); i++) {
if (!mInputBuffers[i].IsValid()) {
continue;
}
device->SetVertexBuffer(1, &mInputBuffers[i]);
device->SetPSTexture(0, mTextures[i].mSource);
device->DrawInstanced(4, mInputBuffers[i].NumVertices(), 0, 0);
}
}
void AppendToMaskTextureList(MaskTextureList& aList, Layer* aLayer) {
RefPtr<TextureSource> source = GetMaskLayerTexture(aLayer);
if (!source) {
return;
}
gfx::Rect rect = ComputeQuadForMaskLayer(aLayer, source->GetSize());
aList.push_back(MaskTexture(rect, source));
}
} // namespace layers
} // namespace mozilla

View File

@ -1,89 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_MaskOperation_h
#define mozilla_gfx_layers_mlgpu_MaskOperation_h
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/Rect.h"
#include "SharedBufferMLGPU.h"
#include <vector>
namespace mozilla {
namespace layers {
class FrameBuilder;
class Layer;
class MLGDevice;
class MLGRenderTarget;
class MLGTexture;
class TextureSource;
class MaskOperation {
NS_INLINE_DECL_REFCOUNTING(MaskOperation)
public:
// For when the exact texture is known ahead of time.
MaskOperation(FrameBuilder* aBuilder, MLGTexture* aSource);
// Return the mask rectangle in screen coordinates. This function takes a
// layer because a single-texture mask operation is not dependent on a
// specific mask transform. (Multiple mask layer operations are, and they
// ignore the layer parameter).
virtual gfx::Rect ComputeMaskRect(Layer* aLayer) const;
MLGTexture* GetTexture() const { return mTexture; }
bool IsEmpty() const { return !mTexture; }
protected:
explicit MaskOperation(FrameBuilder* aBuilder);
virtual ~MaskOperation();
protected:
RefPtr<MLGTexture> mTexture;
};
struct MaskTexture {
MaskTexture() : mSource(nullptr) {}
MaskTexture(const gfx::Rect& aRect, TextureSource* aSource)
: mRect(aRect), mSource(aSource) {}
bool operator<(const MaskTexture& aOther) const;
gfx::Rect mRect;
RefPtr<TextureSource> mSource;
};
typedef std::vector<MaskTexture> MaskTextureList;
class MaskCombineOperation final : public MaskOperation {
public:
explicit MaskCombineOperation(FrameBuilder* aBuilder);
virtual ~MaskCombineOperation();
void Init(const MaskTextureList& aTextures);
void PrepareForRendering();
void Render();
gfx::Rect ComputeMaskRect(Layer* aLayer) const override { return mArea; }
private:
FrameBuilder* mBuilder;
gfx::Rect mArea;
MaskTextureList mTextures;
RefPtr<MLGRenderTarget> mTarget;
std::vector<VertexBufferSection> mInputBuffers;
};
RefPtr<TextureSource> GetMaskLayerTexture(Layer* aLayer);
void AppendToMaskTextureList(MaskTextureList& aList, Layer* aLayer);
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_MaskOperation_h

View File

@ -1,54 +0,0 @@
/* -*- 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 "MemoryReportingMLGPU.h"
#include "nsIMemoryReporter.h"
namespace mozilla {
namespace layers {
namespace mlg {
mozilla::Atomic<size_t> sConstantBufferUsage;
mozilla::Atomic<size_t> sVertexBufferUsage;
mozilla::Atomic<size_t> sRenderTargetUsage;
class MemoryReportingMLGPU final : public nsIMemoryReporter {
public:
NS_DECL_ISUPPORTS
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize) override {
if (sConstantBufferUsage) {
MOZ_COLLECT_REPORT("mlgpu-constant-buffers", KIND_OTHER, UNITS_BYTES,
sConstantBufferUsage,
"Advanced Layers shader constant buffers.");
}
if (sVertexBufferUsage) {
MOZ_COLLECT_REPORT("mlgpu-vertex-buffers", KIND_OTHER, UNITS_BYTES,
sVertexBufferUsage,
"Advanced Layers shader vertex buffers.");
}
if (sRenderTargetUsage) {
MOZ_COLLECT_REPORT(
"mlgpu-render-targets", KIND_OTHER, UNITS_BYTES, sRenderTargetUsage,
"Advanced Layers render target textures and depth buffers.");
}
return NS_OK;
}
private:
~MemoryReportingMLGPU() = default;
};
NS_IMPL_ISUPPORTS(MemoryReportingMLGPU, nsIMemoryReporter);
void InitializeMemoryReporters() {
RegisterStrongMemoryReporter(new MemoryReportingMLGPU());
}
} // namespace mlg
} // namespace layers
} // namespace mozilla

View File

@ -1,26 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_MemoryReportingMLGPU_h
#define mozilla_gfx_layers_mlgpu_MemoryReportingMLGPU_h
#include "mozilla/Atomics.h"
namespace mozilla {
namespace layers {
namespace mlg {
void InitializeMemoryReporters();
extern mozilla::Atomic<size_t> sConstantBufferUsage;
extern mozilla::Atomic<size_t> sVertexBufferUsage;
extern mozilla::Atomic<size_t> sRenderTargetUsage;
} // namespace mlg
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_MemoryReportingMLGPU_h

View File

@ -1,219 +0,0 @@
/* -*- 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 "PaintedLayerMLGPU.h"
#include "LayerManagerMLGPU.h"
#include "mozilla/layers/LayersHelpers.h"
#include "mozilla/layers/TiledContentHost.h"
#include "UnitTransforms.h"
namespace mozilla {
using namespace gfx;
namespace layers {
PaintedLayerMLGPU::PaintedLayerMLGPU(LayerManagerMLGPU* aManager)
: PaintedLayer(aManager, static_cast<HostLayer*>(this)),
LayerMLGPU(aManager) {
MOZ_COUNT_CTOR(PaintedLayerMLGPU);
}
PaintedLayerMLGPU::~PaintedLayerMLGPU() {
MOZ_COUNT_DTOR(PaintedLayerMLGPU);
CleanupResources();
}
bool PaintedLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder) {
// Reset our cached texture pointers. The next call to AssignToView will
// populate them again.
mTexture = nullptr;
mTextureOnWhite = nullptr;
return !!mHost;
}
void PaintedLayerMLGPU::SetRenderRegion(LayerIntRegion&& aRegion) {
mRenderRegion = std::move(aRegion);
LayerIntRect bounds(mRenderRegion.GetBounds().TopLeft(),
ViewAs<LayerPixel>(mTexture->GetSize()));
mRenderRegion.AndWith(bounds);
}
const LayerIntRegion& PaintedLayerMLGPU::GetDrawRects() {
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
// Note: we don't set PaintWillResample on our ContentTextureHost. The old
// compositor must do this since ContentHost is responsible for issuing
// draw calls, but in AL we can handle it directly here.
//
// Note that when AL performs CPU-based occlusion culling (the default
// behavior), we might break up the visible region again. If that turns
// out to be a problem, we can factor this into ForEachDrawRect instead.
if (MayResample()) {
mDrawRects = mRenderRegion.GetBounds();
return mDrawRects;
}
#endif
return mRenderRegion;
}
bool PaintedLayerMLGPU::SetCompositableHost(CompositableHost* aHost) {
switch (aHost->GetType()) {
case CompositableType::CONTENT_TILED:
case CompositableType::CONTENT_SINGLE:
case CompositableType::CONTENT_DOUBLE: {
if (mHost && mHost != aHost->AsContentHost()) {
mHost->Detach(this);
}
mHost = aHost->AsContentHost();
if (!mHost) {
gfxWarning() << "ContentHostBase is not a ContentHostTexture";
}
return true;
}
default:
return false;
}
}
CompositableHost* PaintedLayerMLGPU::GetCompositableHost() { return mHost; }
gfx::Point PaintedLayerMLGPU::GetDestOrigin() const { return mDestOrigin; }
void PaintedLayerMLGPU::AssignToView(FrameBuilder* aBuilder,
RenderViewMLGPU* aView,
Maybe<Polygon>&& aGeometry) {
if (TiledContentHost* tiles = mHost->AsTiledContentHost()) {
// Note: we do not support the low-res buffer yet.
MOZ_ASSERT(tiles->GetLowResBuffer().GetTileCount() == 0);
AssignHighResTilesToView(aBuilder, aView, tiles, aGeometry);
return;
}
// If we don't have a texture yet, acquire one from the ContentHost now.
if (!mTexture) {
ContentHostTexture* single = mHost->AsContentHostTexture();
if (!single) {
return;
}
mTexture = single->AcquireTextureSource();
if (!mTexture) {
return;
}
mTextureOnWhite = single->AcquireTextureSourceOnWhite();
mDestOrigin = single->GetOriginOffset();
}
// Fall through to the single texture case.
LayerMLGPU::AssignToView(aBuilder, aView, std::move(aGeometry));
}
void PaintedLayerMLGPU::AssignHighResTilesToView(
FrameBuilder* aBuilder, RenderViewMLGPU* aView, TiledContentHost* aTileHost,
const Maybe<Polygon>& aGeometry) {
TiledLayerBufferComposite& tiles = aTileHost->GetHighResBuffer();
LayerIntRegion compositeRegion = ViewAs<LayerPixel>(tiles.GetValidRegion());
compositeRegion.AndWith(GetShadowVisibleRegion());
if (compositeRegion.IsEmpty()) {
return;
}
AssignTileBufferToView(aBuilder, aView, tiles, compositeRegion, aGeometry);
}
void PaintedLayerMLGPU::AssignTileBufferToView(
FrameBuilder* aBuilder, RenderViewMLGPU* aView,
TiledLayerBufferComposite& aTiles, const LayerIntRegion& aCompositeRegion,
const Maybe<Polygon>& aGeometry) {
float resolution = aTiles.GetResolution();
// Save these so they can be restored at the end.
float baseOpacity = mComputedOpacity;
LayerIntRegion visible = GetShadowVisibleRegion();
for (size_t i = 0; i < aTiles.GetTileCount(); i++) {
TileHost& tile = aTiles.GetTile(i);
if (tile.IsPlaceholderTile()) {
continue;
}
TileCoordIntPoint coord = aTiles.GetPlacement().TileCoord(i);
// A sanity check that catches a lot of mistakes.
MOZ_ASSERT(coord.x == tile.mTileCoord.x && coord.y == tile.mTileCoord.y);
IntPoint offset = aTiles.GetTileOffset(coord);
// Use LayerIntRect here so we don't have to keep re-allocating the region
// to change the unit type.
LayerIntRect tileRect(ViewAs<LayerPixel>(offset),
ViewAs<LayerPixel>(aTiles.GetScaledTileSize()));
LayerIntRegion tileDrawRegion = tileRect;
tileDrawRegion.AndWith(aCompositeRegion);
if (tileDrawRegion.IsEmpty()) {
continue;
}
tileDrawRegion.ScaleRoundOut(resolution, resolution);
// Update layer state for this tile - that includes the texture, visible
// region, and opacity.
mTexture = tile.AcquireTextureSource();
if (!mTexture) {
continue;
}
mTextureOnWhite = tile.AcquireTextureSourceOnWhite();
SetShadowVisibleRegion(tileDrawRegion);
mComputedOpacity = tile.GetFadeInOpacity(baseOpacity);
mDestOrigin = offset;
// Yes, it's a bit weird that we're assigning the same layer to the same
// view multiple times. Note that each time, the texture, computed
// opacity, origin, and visible region are updated to match the current
// tile, and we restore these properties after we've finished processing
// all tiles.
Maybe<Polygon> geometry = aGeometry;
LayerMLGPU::AssignToView(aBuilder, aView, std::move(geometry));
}
// Restore the computed opacity and visible region.
mComputedOpacity = baseOpacity;
SetShadowVisibleRegion(std::move(visible));
}
void PaintedLayerMLGPU::CleanupResources() {
if (mHost) {
mHost->Detach(this);
}
mTexture = nullptr;
mTextureOnWhite = nullptr;
mHost = nullptr;
}
void PaintedLayerMLGPU::PrintInfo(std::stringstream& aStream,
const char* aPrefix) {
PaintedLayer::PrintInfo(aStream, aPrefix);
if (mHost && mHost->IsAttached()) {
aStream << "\n";
nsAutoCString pfx(aPrefix);
pfx += " ";
mHost->PrintInfo(aStream, pfx.get());
}
}
void PaintedLayerMLGPU::Disconnect() { CleanupResources(); }
bool PaintedLayerMLGPU::IsContentOpaque() {
return !!(GetContentFlags() & CONTENT_OPAQUE);
}
void PaintedLayerMLGPU::CleanupCachedResources() { CleanupResources(); }
} // namespace layers
} // namespace mozilla

View File

@ -1,100 +0,0 @@
/* -*- 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_GFX_PAINTEDLAYERMLGPU_H
#define MOZILLA_GFX_PAINTEDLAYERMLGPU_H
#include "LayerManagerMLGPU.h"
#include "mozilla/layers/ContentHost.h"
#include "mozilla/layers/LayerMLGPU.h"
#include "MLGDeviceTypes.h"
#include "nsRegionFwd.h"
#include <functional>
namespace mozilla {
namespace layers {
class TiledLayerBufferComposite;
class PaintedLayerMLGPU final : public PaintedLayer, public LayerMLGPU {
public:
explicit PaintedLayerMLGPU(LayerManagerMLGPU* aManager);
virtual ~PaintedLayerMLGPU();
// Layer
HostLayer* AsHostLayer() override { return this; }
PaintedLayerMLGPU* AsPaintedLayerMLGPU() override { return this; }
Layer* GetLayer() override { return this; }
bool SetCompositableHost(CompositableHost*) override;
CompositableHost* GetCompositableHost() override;
void Disconnect() override;
bool IsContentOpaque() override;
// PaintedLayer
void InvalidateRegion(const nsIntRegion& aRegion) override {
MOZ_CRASH("PaintedLayerMLGPU can't fill invalidated regions");
}
bool HasComponentAlpha() const { return !!mTextureOnWhite; }
TextureSource* GetTexture() const { return mTexture; }
TextureSource* GetTextureOnWhite() const {
MOZ_ASSERT(HasComponentAlpha());
return mTextureOnWhite;
}
gfx::Point GetDestOrigin() const;
SamplerMode GetSamplerMode() {
// Note that when resamping, we must break the texture coordinates into
// no-repeat rects. When we have simple integer translations we can
// simply wrap around the edge of the buffer texture.
return MayResample() ? SamplerMode::LinearClamp : SamplerMode::LinearRepeat;
}
void SetRenderRegion(LayerIntRegion&& aRegion) override;
// To avoid sampling issues with complex regions and transforms, we
// squash the visible region for PaintedLayers into a single draw
// rect. RenderPasses should use this method instead of GetRenderRegion.
const LayerIntRegion& GetDrawRects();
MOZ_LAYER_DECL_NAME("PaintedLayerMLGPU", TYPE_PAINTED)
void CleanupCachedResources();
protected:
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
// We override this to support tiling.
void AssignToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
Maybe<gfx::Polygon>&& aGeometry) override;
void AssignHighResTilesToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
TiledContentHost* aTileHost,
const Maybe<gfx::Polygon>& aGeometry);
// Helper for Assign*TilesToView.
void AssignTileBufferToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
TiledLayerBufferComposite& aTiles,
const LayerIntRegion& aCompositeRegion,
const Maybe<gfx::Polygon>& aGeometry);
void CleanupResources();
private:
RefPtr<ContentHost> mHost;
RefPtr<TextureSource> mTexture;
RefPtr<TextureSource> mTextureOnWhite;
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
LayerIntRegion mDrawRects;
#endif
gfx::IntPoint mDestOrigin;
};
} // namespace layers
} // namespace mozilla
#endif

View File

@ -1,67 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_RenderPassMLGPU_inl_h
#define mozilla_gfx_layers_mlgpu_RenderPassMLGPU_inl_h
namespace mozilla {
namespace layers {
template <typename Traits>
static inline bool AddShaderTriangles(VertexStagingBuffer* aBuffer,
const Traits& aTraits,
const gfx::Polygon* aGeometry = nullptr) {
typedef typename Traits::TriangleVertices TriangleVertices;
typedef typename Traits::FirstTriangle FirstTriangle;
typedef typename Traits::SecondTriangle SecondTriangle;
if (!aGeometry) {
TriangleVertices base1 = aTraits.MakeVertex(FirstTriangle());
TriangleVertices base2 = aTraits.MakeVertex(SecondTriangle());
auto data1 = aTraits.MakeVertexData(FirstTriangle());
auto data2 = aTraits.MakeVertexData(SecondTriangle());
return aBuffer->PrependItem(base1, data1) &&
aBuffer->PrependItem(base2, data2);
}
auto triangles = aTraits.GenerateTriangles(*aGeometry);
for (const auto& triangle : triangles) {
TriangleVertices base = aTraits.MakeVertex(triangle);
auto data = aTraits.MakeVertexData(triangle);
if (!aBuffer->PrependItem(base, data)) {
return false;
}
}
return true;
}
template <typename Traits>
inline bool BatchRenderPass<Traits>::Txn::AddImpl(const Traits& aTraits) {
VertexStagingBuffer* instances = mPass->GetInstances();
if (mPass->mGeometry == GeometryMode::Polygon) {
if (const Maybe<gfx::Polygon>& geometry = aTraits.geometry()) {
gfx::Polygon polygon = geometry->ClipPolygon(aTraits.rect());
if (polygon.IsEmpty()) {
return true;
}
return AddShaderTriangles(instances, aTraits, &polygon);
}
return AddShaderTriangles(instances, aTraits);
}
typedef typename Traits::UnitQuadVertex UnitQuadVertex;
typedef typename Traits::UnitQuad UnitQuad;
UnitQuadVertex base = aTraits.MakeUnitQuadVertex();
auto data = aTraits.MakeVertexData(UnitQuad());
return instances->AddItem(base, data);
}
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_RenderPassMLGPU_inl_h

View File

@ -1,971 +0,0 @@
/* -*- 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 "RenderPassMLGPU.h"
#include "ContainerLayerMLGPU.h"
#include "FrameBuilder.h"
#include "ImageLayerMLGPU.h"
#include "MaskOperation.h"
#include "MLGDevice.h"
#include "PaintedLayerMLGPU.h"
#include "RenderViewMLGPU.h"
#include "ShaderDefinitionsMLGPU.h"
#include "ShaderDefinitionsMLGPU-inl.h"
#include "SharedBufferMLGPU.h"
#include "mozilla/layers/LayersHelpers.h"
#include "mozilla/layers/LayersMessages.h"
#include "RenderPassMLGPU-inl.h"
namespace mozilla {
namespace layers {
using namespace gfx;
ItemInfo::ItemInfo(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
LayerMLGPU* aLayer, int32_t aSortOrder,
const IntRect& aBounds, Maybe<Polygon>&& aGeometry)
: view(aView),
layer(aLayer),
type(RenderPassType::Unknown),
layerIndex(kInvalidResourceIndex),
sortOrder(aSortOrder),
bounds(aBounds),
geometry(std::move(aGeometry)) {
const Matrix4x4& transform = aLayer->GetLayer()->GetEffectiveTransform();
Matrix transform2D;
if (!geometry && transform.Is2D(&transform2D) &&
transform2D.IsRectilinear()) {
this->rectilinear = true;
if (transform2D.IsIntegerTranslation()) {
this->translation =
Some(IntPoint::Truncate(transform2D.GetTranslation()));
}
} else {
this->rectilinear = false;
}
// Layers can have arbitrary clips or transforms, and we can't use built-in
// scissor functionality when batching. Instead, pixel shaders will write
// transparent pixels for positions outside of the clip. Unfortunately that
// breaks z-buffering because the transparent pixels will still write to
// the depth buffer.
//
// To make this work, we clamp the final vertices in the vertex shader to
// the clip rect. We can only do this for rectilinear transforms. If a
// transform can produce a rotation or perspective change, then we might
// accidentally change the geometry. These items are not treated as
// opaque.
//
// Also, we someday want non-rectilinear items to be antialiased with DEAA,
// and we can't do this if the items are rendered front-to-back, since
// such items cannot be blended. (Though we could consider adding these
// items in two separate draw calls, one for DEAA and for not - that is
// definitely future work.)
if (aLayer->GetComputedOpacity() != 1.0f || aLayer->GetMask() ||
!aLayer->IsContentOpaque() || !rectilinear) {
this->opaque = false;
this->renderOrder = RenderOrder::BackToFront;
} else {
this->opaque = true;
this->renderOrder = aView->HasDepthBuffer() ? RenderOrder::FrontToBack
: RenderOrder::BackToFront;
}
this->type = RenderPassMLGPU::GetPreferredPassType(aBuilder, *this);
}
RenderPassType RenderPassMLGPU::GetPreferredPassType(FrameBuilder* aBuilder,
const ItemInfo& aItem) {
LayerMLGPU* layer = aItem.layer;
switch (layer->GetType()) {
case Layer::TYPE_COLOR: {
if (aBuilder->GetDevice()->CanUseClearView() &&
aItem.HasRectTransformAndClip() && aItem.translation &&
aItem.opaque && !aItem.view->HasDepthBuffer()) {
// Note: we don't have ClearView set up to do depth buffer writes, so we
// exclude depth buffering from the test above.
return RenderPassType::ClearView;
}
return RenderPassType::SolidColor;
}
case Layer::TYPE_PAINTED: {
PaintedLayerMLGPU* painted = layer->AsPaintedLayerMLGPU();
if (painted->HasComponentAlpha()) {
return RenderPassType::ComponentAlpha;
}
return RenderPassType::SingleTexture;
}
case Layer::TYPE_CANVAS:
return RenderPassType::SingleTexture;
case Layer::TYPE_IMAGE: {
ImageHost* host = layer->AsTexturedLayerMLGPU()->GetImageHost();
TextureHost* texture = host->CurrentTextureHost();
if (texture->GetReadFormat() == SurfaceFormat::YUV ||
texture->GetReadFormat() == SurfaceFormat::NV12 ||
texture->GetReadFormat() == SurfaceFormat::P010 ||
texture->GetReadFormat() == SurfaceFormat::P016) {
return RenderPassType::Video;
}
return RenderPassType::SingleTexture;
}
case Layer::TYPE_CONTAINER:
return RenderPassType::RenderView;
default:
return RenderPassType::Unknown;
}
}
RefPtr<RenderPassMLGPU> RenderPassMLGPU::CreatePass(FrameBuilder* aBuilder,
const ItemInfo& aItem) {
switch (aItem.type) {
case RenderPassType::SolidColor:
return MakeAndAddRef<SolidColorPass>(aBuilder, aItem);
case RenderPassType::SingleTexture:
return MakeAndAddRef<SingleTexturePass>(aBuilder, aItem);
case RenderPassType::RenderView:
return MakeAndAddRef<RenderViewPass>(aBuilder, aItem);
case RenderPassType::Video:
return MakeAndAddRef<VideoRenderPass>(aBuilder, aItem);
case RenderPassType::ComponentAlpha:
return MakeAndAddRef<ComponentAlphaPass>(aBuilder, aItem);
case RenderPassType::ClearView:
return MakeAndAddRef<ClearViewPass>(aBuilder, aItem);
default:
return nullptr;
}
}
RenderPassMLGPU::RenderPassMLGPU(FrameBuilder* aBuilder, const ItemInfo& aItem)
: mBuilder(aBuilder),
mDevice(aBuilder->GetDevice()),
mLayerBufferIndex(aBuilder->CurrentLayerBufferIndex()),
mMaskRectBufferIndex(kInvalidResourceIndex),
mPrepared(false) {}
RenderPassMLGPU::~RenderPassMLGPU() = default;
bool RenderPassMLGPU::IsCompatible(const ItemInfo& aItem) {
if (GetType() != aItem.type) {
return false;
}
if (mLayerBufferIndex != mBuilder->CurrentLayerBufferIndex()) {
return false;
}
return true;
}
bool RenderPassMLGPU::AcceptItem(ItemInfo& aInfo) {
MOZ_ASSERT(IsCompatible(aInfo));
if (!AddToPass(aInfo.layer, aInfo)) {
return false;
}
if (aInfo.renderOrder == RenderOrder::BackToFront) {
mAffectedRegion.OrWith(aInfo.bounds);
mAffectedRegion.SimplifyOutward(4);
}
return true;
}
bool RenderPassMLGPU::Intersects(const ItemInfo& aItem) {
MOZ_ASSERT(aItem.renderOrder == RenderOrder::BackToFront);
return !mAffectedRegion.Intersect(aItem.bounds).IsEmpty();
}
void RenderPassMLGPU::PrepareForRendering() { mPrepared = true; }
ShaderRenderPass::ShaderRenderPass(FrameBuilder* aBuilder,
const ItemInfo& aItem)
: RenderPassMLGPU(aBuilder, aItem),
mGeometry(GeometryMode::Unknown),
mHasRectTransformAndClip(aItem.HasRectTransformAndClip()) {
mMask = aItem.layer->GetMask();
if (mMask) {
mMaskRectBufferIndex = mBuilder->CurrentMaskRectBufferIndex();
}
}
bool ShaderRenderPass::IsCompatible(const ItemInfo& aItem) {
MOZ_ASSERT(mGeometry != GeometryMode::Unknown);
if (!RenderPassMLGPU::IsCompatible(aItem)) {
return false;
}
// A masked batch cannot accept non-masked items, since the pixel shader
// bakes in whether a mask is present. Also, the pixel shader can only bind
// one specific mask at a time.
if (aItem.layer->GetMask() != mMask) {
return false;
}
if (mMask && mBuilder->CurrentMaskRectBufferIndex() != mMaskRectBufferIndex) {
return false;
}
// We key batches on this property, since we can use more efficient pixel
// shaders if we don't need to propagate a clip and a mask.
if (mHasRectTransformAndClip != aItem.HasRectTransformAndClip()) {
return false;
}
// We should be assured at this point, that if the item requires complex
// geometry, then it should have already been rejected from a unit-quad
// batch. Therefore this batch should be in polygon mode.
MOZ_ASSERT_IF(aItem.geometry.isSome(), mGeometry == GeometryMode::Polygon);
return true;
}
void ShaderRenderPass::SetGeometry(const ItemInfo& aItem, GeometryMode aMode) {
MOZ_ASSERT(mGeometry == GeometryMode::Unknown);
if (aMode == GeometryMode::Unknown) {
mGeometry = mHasRectTransformAndClip ? GeometryMode::UnitQuad
: GeometryMode::Polygon;
} else {
mGeometry = aMode;
}
// Since we process layers front-to-back, back-to-front items are
// in the wrong order. We address this by automatically reversing
// the buffers we use to build vertices.
if (aItem.renderOrder != RenderOrder::FrontToBack) {
mInstances.SetReversed();
}
}
void ShaderRenderPass::PrepareForRendering() {
if (mInstances.IsEmpty()) {
return;
}
if (!mDevice->GetSharedVertexBuffer()->Allocate(&mInstanceBuffer,
mInstances) ||
!SetupPSBuffer0(GetOpacity()) || !OnPrepareBuffers()) {
return;
}
return RenderPassMLGPU::PrepareForRendering();
}
bool ShaderRenderPass::SetupPSBuffer0(float aOpacity) {
if (aOpacity == 1.0f && !HasMask()) {
mPSBuffer0 = mBuilder->GetDefaultMaskInfo();
return true;
}
MaskInformation cb(aOpacity, HasMask());
return mDevice->GetSharedPSBuffer()->Allocate(&mPSBuffer0, cb);
}
void ShaderRenderPass::ExecuteRendering() {
if (mInstances.IsEmpty()) {
return;
}
// Change the blend state if needed.
if (Maybe<MLGBlendState> blendState = GetBlendState()) {
mDevice->SetBlendState(blendState.value());
}
mDevice->SetPSConstantBuffer(0, &mPSBuffer0);
if (MaskOperation* mask = GetMask()) {
mDevice->SetPSTexture(kMaskLayerTextureSlot, mask->GetTexture());
mDevice->SetSamplerMode(kMaskSamplerSlot, SamplerMode::LinearClampToZero);
}
SetupPipeline();
if (mGeometry == GeometryMode::Polygon) {
mDevice->SetTopology(MLGPrimitiveTopology::UnitTriangle);
} else {
mDevice->SetTopology(MLGPrimitiveTopology::UnitQuad);
}
mDevice->SetVertexBuffer(1, &mInstanceBuffer);
if (mGeometry == GeometryMode::Polygon) {
mDevice->DrawInstanced(3, mInstanceBuffer.NumVertices(), 0, 0);
} else {
mDevice->DrawInstanced(4, mInstanceBuffer.NumVertices(), 0, 0);
}
}
static inline DeviceColor ComputeLayerColor(LayerMLGPU* aLayer,
const DeviceColor& aColor) {
float opacity = aLayer->GetComputedOpacity();
return DeviceColor(aColor.r * aColor.a * opacity,
aColor.g * aColor.a * opacity,
aColor.b * aColor.a * opacity, aColor.a * opacity);
}
ClearViewPass::ClearViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
: RenderPassMLGPU(aBuilder, aItem), mView(aItem.view) {
// Note: we could write to the depth buffer, but since the depth buffer is
// disabled by default, we don't bother yet.
MOZ_ASSERT(!mView->HasDepthBuffer());
ColorLayer* colorLayer = aItem.layer->GetLayer()->AsColorLayer();
mColor = ComputeLayerColor(aItem.layer, colorLayer->GetColor());
}
bool ClearViewPass::IsCompatible(const ItemInfo& aItem) {
if (!RenderPassMLGPU::IsCompatible(aItem)) {
return false;
}
// These should be true if we computed a ClearView pass type.
MOZ_ASSERT(aItem.translation);
MOZ_ASSERT(aItem.opaque);
MOZ_ASSERT(aItem.HasRectTransformAndClip());
// Each call only supports a single color.
ColorLayer* colorLayer = aItem.layer->GetLayer()->AsColorLayer();
if (mColor != ComputeLayerColor(aItem.layer, colorLayer->GetColor())) {
return false;
}
// We don't support opacity here since it would not blend correctly.
MOZ_ASSERT(mColor.a == 1.0f);
return true;
}
bool ClearViewPass::AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) {
const LayerIntRegion& region = aItem->GetRenderRegion();
for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
IntRect rect = iter.Get().ToUnknownRect();
rect += aInfo.translation.value();
rect -= mView->GetTargetOffset();
mRects.AppendElement(rect);
}
return true;
}
void ClearViewPass::ExecuteRendering() {
mDevice->ClearView(mDevice->GetRenderTarget(), mColor, mRects.Elements(),
mRects.Length());
}
SolidColorPass::SolidColorPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
: BatchRenderPass(aBuilder, aItem) {
SetDefaultGeometry(aItem);
}
bool SolidColorPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aInfo) {
MOZ_ASSERT(aLayer->GetType() == Layer::TYPE_COLOR);
ColorLayer* colorLayer = aLayer->GetLayer()->AsColorLayer();
Txn txn(this);
gfx::DeviceColor color = ComputeLayerColor(aLayer, colorLayer->GetColor());
const LayerIntRegion& region = aLayer->GetRenderRegion();
for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
const IntRect rect = iter.Get().ToUnknownRect();
ColorTraits traits(aInfo, Rect(rect), color);
if (!txn.Add(traits)) {
return false;
}
}
return txn.Commit();
}
float SolidColorPass::GetOpacity() const {
// Note our pixel shader just ignores the opacity, since we baked it
// into our color values already. Just return 1, which ensures we can
// use the default constant buffer binding.
return 1.0f;
}
void SolidColorPass::SetupPipeline() {
if (mGeometry == GeometryMode::UnitQuad) {
mDevice->SetVertexShader(VertexShaderID::ColoredQuad);
mDevice->SetPixelShader(PixelShaderID::ColoredQuad);
} else {
mDevice->SetVertexShader(VertexShaderID::ColoredVertex);
mDevice->SetPixelShader(PixelShaderID::ColoredVertex);
}
}
TexturedRenderPass::TexturedRenderPass(FrameBuilder* aBuilder,
const ItemInfo& aItem)
: BatchRenderPass(aBuilder, aItem), mTextureFlags(TextureFlags::NO_FLAGS) {}
TexturedRenderPass::Info::Info(const ItemInfo& aItem, PaintedLayerMLGPU* aLayer)
: item(aItem),
textureSize(aLayer->GetTexture()->GetSize()),
destOrigin(aLayer->GetDestOrigin()),
decomposeIntoNoRepeatRects(aLayer->MayResample()) {}
TexturedRenderPass::Info::Info(const ItemInfo& aItem,
TexturedLayerMLGPU* aLayer)
: item(aItem),
textureSize(aLayer->GetTexture()->GetSize()),
scale(aLayer->GetPictureScale()),
decomposeIntoNoRepeatRects(false) {}
TexturedRenderPass::Info::Info(const ItemInfo& aItem,
ContainerLayerMLGPU* aLayer)
: item(aItem),
textureSize(aLayer->GetTargetSize()),
destOrigin(aLayer->GetTargetOffset()),
decomposeIntoNoRepeatRects(false) {}
bool TexturedRenderPass::AddItem(Txn& aTxn, const Info& aInfo,
const Rect& aDrawRect) {
if (mGeometry == GeometryMode::Polygon) {
// This path will not clamp the draw rect to the layer clip, so we can pass
// the draw rect texture rects straight through.
return AddClippedItem(aTxn, aInfo, aDrawRect);
}
const ItemInfo& item = aInfo.item;
MOZ_ASSERT(!item.geometry);
MOZ_ASSERT(item.HasRectTransformAndClip());
MOZ_ASSERT(mHasRectTransformAndClip);
const Matrix4x4& fullTransform =
item.layer->GetLayer()->GetEffectiveTransformForBuffer();
Matrix transform = fullTransform.As2D();
Matrix inverse = transform;
if (!inverse.Invert()) {
// Degenerate transforms are not visible, since there is no mapping to
// screen space. Just return without adding any draws.
return true;
}
MOZ_ASSERT(inverse.IsRectilinear());
// Transform the clip rect.
IntRect clipRect = item.layer->GetComputedClipRect().ToUnknownRect();
clipRect += item.view->GetTargetOffset();
// Clip and adjust the texture rect.
Rect localClip = inverse.TransformBounds(Rect(clipRect));
Rect clippedDrawRect = aDrawRect.Intersect(localClip);
if (clippedDrawRect.IsEmpty()) {
return true;
}
return AddClippedItem(aTxn, aInfo, clippedDrawRect);
}
bool TexturedRenderPass::AddClippedItem(Txn& aTxn, const Info& aInfo,
const gfx::Rect& aDrawRect) {
float xScale = 1.0;
float yScale = 1.0;
if (aInfo.scale) {
xScale = aInfo.scale->width;
yScale = aInfo.scale->height;
}
Point offset = aDrawRect.TopLeft() - aInfo.destOrigin;
Rect textureRect(offset.x * xScale, offset.y * yScale,
aDrawRect.Width() * xScale, aDrawRect.Height() * yScale);
Rect textureCoords = TextureRectToCoords(textureRect, aInfo.textureSize);
if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
textureCoords.MoveToY(1.0 - textureCoords.Y());
textureCoords.SetHeight(-textureCoords.Height());
}
if (!aInfo.decomposeIntoNoRepeatRects) {
// Fast, normal case, we can use the texture coordinates as-s and the caller
// will use a repeat sampler if needed.
TexturedTraits traits(aInfo.item, aDrawRect, textureCoords);
if (!aTxn.Add(traits)) {
return false;
}
} else {
Rect layerRects[4];
Rect textureRects[4];
size_t numRects = DecomposeIntoNoRepeatRects(aDrawRect, textureCoords,
&layerRects, &textureRects);
for (size_t i = 0; i < numRects; i++) {
TexturedTraits traits(aInfo.item, layerRects[i], textureRects[i]);
if (!aTxn.Add(traits)) {
return false;
}
}
}
return true;
}
SingleTexturePass::SingleTexturePass(FrameBuilder* aBuilder,
const ItemInfo& aItem)
: TexturedRenderPass(aBuilder, aItem),
mSamplerMode(SamplerMode::LinearClamp),
mOpacity(1.0f) {
SetDefaultGeometry(aItem);
}
bool SingleTexturePass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) {
RefPtr<TextureSource> texture;
SamplerMode sampler;
TextureFlags flags = TextureFlags::NO_FLAGS;
if (PaintedLayerMLGPU* paintedLayer = aLayer->AsPaintedLayerMLGPU()) {
if (paintedLayer->HasComponentAlpha()) {
return false;
}
texture = paintedLayer->GetTexture();
sampler = paintedLayer->GetSamplerMode();
} else if (TexturedLayerMLGPU* texLayer = aLayer->AsTexturedLayerMLGPU()) {
texture = texLayer->GetTexture();
sampler = FilterToSamplerMode(texLayer->GetSamplingFilter());
TextureHost* host = texLayer->GetImageHost()->CurrentTextureHost();
flags = host->GetFlags();
} else {
return false;
}
// We should not assign a texture-based layer to tiles if it has no texture.
MOZ_ASSERT(texture);
float opacity = aLayer->GetComputedOpacity();
if (mTexture) {
if (texture != mTexture) {
return false;
}
if (mSamplerMode != sampler) {
return false;
}
if (mOpacity != opacity) {
return false;
}
// Note: premultiplied, origin-bottom-left are already implied by the
// texture source.
} else {
mTexture = texture;
mSamplerMode = sampler;
mOpacity = opacity;
mTextureFlags = flags;
}
Txn txn(this);
// Note: these are two separate cases since no Info constructor takes in a
// base LayerMLGPU class.
if (PaintedLayerMLGPU* layer = aLayer->AsPaintedLayerMLGPU()) {
Info info(aItem, layer);
if (!AddItems(txn, info, layer->GetDrawRects())) {
return false;
}
} else if (TexturedLayerMLGPU* layer = aLayer->AsTexturedLayerMLGPU()) {
Info info(aItem, layer);
if (!AddItems(txn, info, layer->GetRenderRegion())) {
return false;
}
}
return txn.Commit();
}
Maybe<MLGBlendState> SingleTexturePass::GetBlendState() const {
return (mTextureFlags & TextureFlags::NON_PREMULTIPLIED)
? Some(MLGBlendState::OverAndPremultiply)
: Some(MLGBlendState::Over);
}
void SingleTexturePass::SetupPipeline() {
MOZ_ASSERT(mTexture);
if (mGeometry == GeometryMode::UnitQuad) {
mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
} else {
mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
}
mDevice->SetPSTexture(0, mTexture);
mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode);
switch (mTexture.get()->GetFormat()) {
case SurfaceFormat::B8G8R8A8:
case SurfaceFormat::R8G8B8A8:
if (mGeometry == GeometryMode::UnitQuad)
mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGBA);
else
mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGBA);
break;
default:
if (mGeometry == GeometryMode::UnitQuad)
mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGB);
else
mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGB);
break;
}
}
ComponentAlphaPass::ComponentAlphaPass(FrameBuilder* aBuilder,
const ItemInfo& aItem)
: TexturedRenderPass(aBuilder, aItem),
mOpacity(1.0f),
mSamplerMode(SamplerMode::LinearClamp) {
SetDefaultGeometry(aItem);
}
bool ComponentAlphaPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) {
PaintedLayerMLGPU* layer = aLayer->AsPaintedLayerMLGPU();
MOZ_ASSERT(layer);
if (mTextureOnBlack) {
if (layer->GetTexture() != mTextureOnBlack ||
layer->GetTextureOnWhite() != mTextureOnWhite ||
layer->GetOpacity() != mOpacity ||
layer->GetSamplerMode() != mSamplerMode) {
return false;
}
} else {
mOpacity = layer->GetComputedOpacity();
mSamplerMode = layer->GetSamplerMode();
mTextureOnBlack = layer->GetTexture();
mTextureOnWhite = layer->GetTextureOnWhite();
}
Txn txn(this);
Info info(aItem, layer);
if (!AddItems(txn, info, layer->GetDrawRects())) {
return false;
}
return txn.Commit();
}
float ComponentAlphaPass::GetOpacity() const { return mOpacity; }
void ComponentAlphaPass::SetupPipeline() {
TextureSource* textures[2] = {mTextureOnBlack, mTextureOnWhite};
MOZ_ASSERT(textures[0]);
MOZ_ASSERT(textures[1]);
if (mGeometry == GeometryMode::UnitQuad) {
mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
mDevice->SetPixelShader(PixelShaderID::ComponentAlphaQuad);
} else {
mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
mDevice->SetPixelShader(PixelShaderID::ComponentAlphaVertex);
}
mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode);
mDevice->SetPSTextures(0, 2, textures);
}
VideoRenderPass::VideoRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
: TexturedRenderPass(aBuilder, aItem),
mSamplerMode(SamplerMode::LinearClamp),
mOpacity(1.0f) {
SetDefaultGeometry(aItem);
}
bool VideoRenderPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) {
ImageLayerMLGPU* layer = aLayer->AsImageLayerMLGPU();
if (!layer) {
return false;
}
RefPtr<TextureHost> host = layer->GetImageHost()->CurrentTextureHost();
RefPtr<TextureSource> source = layer->GetTexture();
float opacity = layer->GetComputedOpacity();
SamplerMode sampler = FilterToSamplerMode(layer->GetSamplingFilter());
if (mHost) {
if (mHost != host) {
return false;
}
if (mTexture != source) {
return false;
}
if (mOpacity != opacity) {
return false;
}
if (mSamplerMode != sampler) {
return false;
}
} else {
mHost = host;
mTexture = source;
mOpacity = opacity;
mSamplerMode = sampler;
}
MOZ_ASSERT(!mTexture->AsBigImageIterator());
MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::NON_PREMULTIPLIED));
MOZ_ASSERT(!(mHost->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT));
Txn txn(this);
Info info(aItem, layer);
if (!AddItems(txn, info, layer->GetRenderRegion())) {
return false;
}
return txn.Commit();
}
void VideoRenderPass::SetupPipeline() {
YUVColorSpace colorSpace = YUVColorSpace::UNKNOWN;
switch (mHost->GetReadFormat()) {
case SurfaceFormat::YUV:
case SurfaceFormat::NV12:
case SurfaceFormat::P010:
case SurfaceFormat::P016:
colorSpace = mHost->GetYUVColorSpace();
break;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected surface format in VideoRenderPass");
break;
}
MOZ_ASSERT(colorSpace != YUVColorSpace::UNKNOWN);
RefPtr<MLGBuffer> ps1 = mDevice->GetBufferForColorSpace(colorSpace);
if (!ps1) {
return;
}
RefPtr<MLGBuffer> ps2 =
mDevice->GetBufferForColorDepthCoefficient(mHost->GetColorDepth());
if (!ps2) {
return;
}
if (mGeometry == GeometryMode::UnitQuad) {
mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
} else {
mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
}
switch (mHost->GetReadFormat()) {
case SurfaceFormat::YUV: {
if (colorSpace == YUVColorSpace::Identity) {
if (mGeometry == GeometryMode::UnitQuad)
mDevice->SetPixelShader(PixelShaderID::TexturedQuadIdentityIMC4);
else
mDevice->SetPixelShader(PixelShaderID::TexturedVertexIdentityIMC4);
} else {
if (mGeometry == GeometryMode::UnitQuad)
mDevice->SetPixelShader(PixelShaderID::TexturedQuadIMC4);
else
mDevice->SetPixelShader(PixelShaderID::TexturedVertexIMC4);
}
mDevice->SetPSTexturesYUV(0, mTexture);
break;
}
case SurfaceFormat::NV12:
case SurfaceFormat::P010:
case SurfaceFormat::P016:
if (mGeometry == GeometryMode::UnitQuad)
mDevice->SetPixelShader(PixelShaderID::TexturedQuadNV12);
else
mDevice->SetPixelShader(PixelShaderID::TexturedVertexNV12);
mDevice->SetPSTexturesNV12(0, mTexture);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown video format");
break;
}
mDevice->SetSamplerMode(kDefaultSamplerSlot, mSamplerMode);
mDevice->SetPSConstantBuffer(1, ps1);
mDevice->SetPSConstantBuffer(2, ps2);
}
RenderViewPass::RenderViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
: TexturedRenderPass(aBuilder, aItem), mParentView(nullptr) {
mAssignedLayer = aItem.layer->AsContainerLayerMLGPU();
CompositionOp blendOp = mAssignedLayer->GetMixBlendMode();
if (BlendOpIsMixBlendMode(blendOp)) {
mBlendMode = Some(blendOp);
}
if (mBlendMode) {
// We do not have fast-path rect shaders for blending.
SetGeometry(aItem, GeometryMode::Polygon);
} else {
SetDefaultGeometry(aItem);
}
}
bool RenderViewPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aItem) {
// We bake in the layer ahead of time, which also guarantees the blend mode
// is baked in, as well as the geometry requirement.
if (mAssignedLayer != aLayer) {
return false;
}
mSource = mAssignedLayer->GetRenderTarget();
if (!mSource) {
return false;
}
mParentView = aItem.view;
Txn txn(this);
IntPoint offset = mAssignedLayer->GetTargetOffset();
IntSize size = mAssignedLayer->GetTargetSize();
// Clamp the visible region to the texture size.
nsIntRegion visible = mAssignedLayer->GetRenderRegion().ToUnknownRegion();
visible.AndWith(IntRect(offset, size));
Info info(aItem, mAssignedLayer);
if (!AddItems(txn, info, visible)) {
return false;
}
return txn.Commit();
}
float RenderViewPass::GetOpacity() const {
return mAssignedLayer->GetLayer()->GetEffectiveOpacity();
}
bool RenderViewPass::OnPrepareBuffers() {
if (mBlendMode && !PrepareBlendState()) {
return false;
}
return true;
}
static inline PixelShaderID GetShaderForBlendMode(CompositionOp aOp) {
switch (aOp) {
case CompositionOp::OP_MULTIPLY:
return PixelShaderID::BlendMultiply;
case CompositionOp::OP_SCREEN:
return PixelShaderID::BlendScreen;
case CompositionOp::OP_OVERLAY:
return PixelShaderID::BlendOverlay;
case CompositionOp::OP_DARKEN:
return PixelShaderID::BlendDarken;
case CompositionOp::OP_LIGHTEN:
return PixelShaderID::BlendLighten;
case CompositionOp::OP_COLOR_DODGE:
return PixelShaderID::BlendColorDodge;
case CompositionOp::OP_COLOR_BURN:
return PixelShaderID::BlendColorBurn;
case CompositionOp::OP_HARD_LIGHT:
return PixelShaderID::BlendHardLight;
case CompositionOp::OP_SOFT_LIGHT:
return PixelShaderID::BlendSoftLight;
case CompositionOp::OP_DIFFERENCE:
return PixelShaderID::BlendDifference;
case CompositionOp::OP_EXCLUSION:
return PixelShaderID::BlendExclusion;
case CompositionOp::OP_HUE:
return PixelShaderID::BlendHue;
case CompositionOp::OP_SATURATION:
return PixelShaderID::BlendSaturation;
case CompositionOp::OP_COLOR:
return PixelShaderID::BlendColor;
case CompositionOp::OP_LUMINOSITY:
return PixelShaderID::BlendLuminosity;
default:
MOZ_ASSERT_UNREACHABLE("Unexpected blend mode");
return PixelShaderID::TexturedVertexRGBA;
}
}
bool RenderViewPass::PrepareBlendState() {
Rect visibleRect(
mAssignedLayer->GetRenderRegion().GetBounds().ToUnknownRect());
IntRect clipRect(mAssignedLayer->GetComputedClipRect().ToUnknownRect());
const Matrix4x4& transform =
mAssignedLayer->GetLayer()->GetEffectiveTransformForBuffer();
// Note that we must use our parent RenderView for this calculation,
// since we're copying the backdrop, not our actual local target.
IntRect rtRect(mParentView->GetTargetOffset(), mParentView->GetSize());
Matrix4x4 backdropTransform;
mBackdropCopyRect = ComputeBackdropCopyRect(visibleRect, clipRect, transform,
rtRect, &backdropTransform);
AutoBufferUpload<BlendVertexShaderConstants> cb;
if (!mDevice->GetSharedVSBuffer()->Allocate(&mBlendConstants, &cb)) {
return false;
}
memcpy(cb->backdropTransform, &backdropTransform._11, 64);
return true;
}
void RenderViewPass::SetupPipeline() {
if (mBlendMode) {
RefPtr<MLGRenderTarget> backdrop = mParentView->GetRenderTarget();
MOZ_ASSERT(mDevice->GetRenderTarget() == backdrop);
RefPtr<MLGTexture> copy = mDevice->CreateTexture(
mBackdropCopyRect.Size(), SurfaceFormat::B8G8R8A8, MLGUsage::Default,
MLGTextureFlags::ShaderResource);
if (!copy) {
return;
}
mDevice->CopyTexture(copy, IntPoint(0, 0), backdrop->GetTexture(),
mBackdropCopyRect);
MOZ_ASSERT(mGeometry == GeometryMode::Polygon);
mDevice->SetVertexShader(VertexShaderID::BlendVertex);
mDevice->SetPixelShader(GetShaderForBlendMode(mBlendMode.value()));
mDevice->SetVSConstantBuffer(kBlendConstantBufferSlot, &mBlendConstants);
mDevice->SetPSTexture(1, copy);
} else {
if (mGeometry == GeometryMode::UnitQuad) {
mDevice->SetVertexShader(VertexShaderID::TexturedQuad);
mDevice->SetPixelShader(PixelShaderID::TexturedQuadRGBA);
} else {
mDevice->SetVertexShader(VertexShaderID::TexturedVertex);
mDevice->SetPixelShader(PixelShaderID::TexturedVertexRGBA);
}
}
mDevice->SetPSTexture(0, mSource->GetTexture());
mDevice->SetSamplerMode(kDefaultSamplerSlot, SamplerMode::LinearClamp);
}
void RenderViewPass::ExecuteRendering() {
if (mAssignedLayer->NeedsSurfaceCopy()) {
RenderWithBackdropCopy();
return;
}
TexturedRenderPass::ExecuteRendering();
}
void RenderViewPass::RenderWithBackdropCopy() {
MOZ_ASSERT(mAssignedLayer->NeedsSurfaceCopy());
DebugOnly<Matrix> transform2d;
const Matrix4x4& transform = mAssignedLayer->GetEffectiveTransform();
MOZ_ASSERT(transform.Is2D(&transform2d) &&
!gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
IntPoint translation = IntPoint::Truncate(transform._41, transform._42);
RenderViewMLGPU* childView = mAssignedLayer->GetRenderView();
IntRect visible =
mAssignedLayer->GetRenderRegion().GetBounds().ToUnknownRect();
IntRect sourceRect = visible + translation - mParentView->GetTargetOffset();
IntPoint destPoint = visible.TopLeft() - childView->GetTargetOffset();
RefPtr<MLGTexture> dest = mAssignedLayer->GetRenderTarget()->GetTexture();
RefPtr<MLGTexture> source = mParentView->GetRenderTarget()->GetTexture();
// Clamp the source rect to the source texture size.
sourceRect = sourceRect.Intersect(IntRect(IntPoint(0, 0), source->GetSize()));
// Clamp the source rect to the destination texture size.
IntRect destRect(destPoint, sourceRect.Size());
destRect = destRect.Intersect(IntRect(IntPoint(0, 0), dest->GetSize()));
sourceRect =
sourceRect.Intersect(IntRect(sourceRect.TopLeft(), destRect.Size()));
mDevice->CopyTexture(dest, destPoint, source, sourceRect);
childView->RenderAfterBackdropCopy();
mParentView->RestoreDeviceState();
TexturedRenderPass::ExecuteRendering();
}
} // namespace layers
} // namespace mozilla

View File

@ -1,439 +0,0 @@
/* -*- 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_GFX_RENDERPASSMLGPU_H
#define MOZILLA_GFX_RENDERPASSMLGPU_H
#include "LayerMLGPU.h"
#include "LayerManagerMLGPU.h"
#include "ShaderDefinitionsMLGPU.h"
#include "SharedBufferMLGPU.h"
#include "StagingBuffer.h"
namespace mozilla {
namespace layers {
using namespace mlg;
class RenderViewMLGPU;
enum class RenderPassType {
ClearView,
SolidColor,
SingleTexture,
RenderView,
Video,
ComponentAlpha,
Unknown
};
enum class RenderOrder {
// Used for all items when not using a depth buffer. Otherwise, used for
// items that may draw transparent pixels.
BackToFront,
// Only used when the depth buffer is enabled, and only for items that are
// guaranteed to only draw opaque pixels.
FrontToBack
};
static const uint32_t kInvalidResourceIndex = uint32_t(-1);
struct ItemInfo final {
ItemInfo(FrameBuilder* aBuilder, RenderViewMLGPU* aView, LayerMLGPU* aLayer,
int32_t aSortOrder, const gfx::IntRect& aBounds,
Maybe<gfx::Polygon>&& aGeometry);
// Return true if a layer can be clipped by the vertex shader; false
// otherwise. Any kind of textured mask or non-rectilinear transform
// will cause this to return false.
bool HasRectTransformAndClip() const {
return rectilinear && !layer->GetMask();
}
RenderViewMLGPU* view;
LayerMLGPU* layer;
RenderPassType type;
uint32_t layerIndex;
int32_t sortOrder;
gfx::IntRect bounds;
RenderOrder renderOrder;
Maybe<gfx::Polygon> geometry;
// Set only when the transform is a 2D integer translation.
Maybe<gfx::IntPoint> translation;
// Set when the item bounds will occlude anything below it.
bool opaque;
// Set when the item's transform is 2D and rectilinear.
bool rectilinear;
};
// Base class for anything that can render in a batch to the GPU.
class RenderPassMLGPU {
NS_INLINE_DECL_REFCOUNTING(RenderPassMLGPU)
public:
static RenderPassType GetPreferredPassType(FrameBuilder* aBuilder,
const ItemInfo& aInfo);
static RefPtr<RenderPassMLGPU> CreatePass(FrameBuilder* aBuilder,
const ItemInfo& aInfo);
// Return true if this pass is compatible with the given item, false
// otherwise. This does not guarantee the pass will accept the item,
// but does guarantee we can try.
virtual bool IsCompatible(const ItemInfo& aItem);
virtual RenderPassType GetType() const = 0;
// Return true if the layer was compatible with and added to this pass,
// false otherwise.
bool AcceptItem(ItemInfo& aInfo);
// Prepare constants buffers and textures.
virtual void PrepareForRendering();
// Execute this render pass to the currently selected surface.
virtual void ExecuteRendering() = 0;
virtual Maybe<MLGBlendState> GetBlendState() const { return Nothing(); }
size_t GetLayerBufferIndex() const { return mLayerBufferIndex; }
Maybe<uint32_t> GetMaskRectBufferIndex() const {
return mMaskRectBufferIndex == kInvalidResourceIndex
? Nothing()
: Some(mMaskRectBufferIndex);
}
// Returns true if this pass overlaps the affected region of an item. This
// only ever returns true for transparent items and transparent batches,
// and should not be used otherwise.
bool Intersects(const ItemInfo& aItem);
// Returns true if pass has been successfully prepared.
bool IsPrepared() const { return mPrepared; }
protected:
RenderPassMLGPU(FrameBuilder* aBuilder, const ItemInfo& aItem);
virtual ~RenderPassMLGPU();
// Return true if the item was consumed, false otherwise.
virtual bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) = 0;
protected:
enum class GeometryMode { Unknown, UnitQuad, Polygon };
protected:
FrameBuilder* mBuilder;
RefPtr<MLGDevice> mDevice;
size_t mLayerBufferIndex;
size_t mMaskRectBufferIndex;
gfx::IntRegion mAffectedRegion;
bool mPrepared;
};
// Shader-based render passes execute a draw call, vs. non-shader passes that
// use non-shader APIs (like ClearView).
class ShaderRenderPass : public RenderPassMLGPU {
public:
ShaderRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
// Used by ShaderDefinitions for writing traits.
VertexStagingBuffer* GetInstances() { return &mInstances; }
bool IsCompatible(const ItemInfo& aItem) override;
void PrepareForRendering() override;
void ExecuteRendering() override;
Maybe<MLGBlendState> GetBlendState() const override {
return Some(MLGBlendState::Over);
}
protected:
// If this batch has a uniform opacity, return it here. Otherwise this should
// return 1.0.
virtual float GetOpacity() const = 0;
// Set any components of the pipeline that won't be handled by
// ExecuteRendering. This is called only once even if multiple draw calls
// are issued.
virtual void SetupPipeline() = 0;
protected:
// Set the geometry this pass will use. This must be called by every
// derived constructor. Use GeometryMode::Unknown to pick the default
// behavior: UnitQuads for rectilinear transform+clips, and polygons
// otherwise.
void SetGeometry(const ItemInfo& aItem, GeometryMode aMode);
void SetDefaultGeometry(const ItemInfo& aItem) {
SetGeometry(aItem, GeometryMode::Unknown);
}
// Called after PrepareForRendering() has finished. If this returns false,
// PrepareForRendering() will return false.
virtual bool OnPrepareBuffers() { return true; }
// Prepare the mask/opacity buffer bound in most pixel shaders.
bool SetupPSBuffer0(float aOpacity);
bool HasMask() const { return !!mMask; }
MaskOperation* GetMask() const { return mMask; }
protected:
GeometryMode mGeometry;
RefPtr<MaskOperation> mMask;
bool mHasRectTransformAndClip;
VertexStagingBuffer mInstances;
VertexBufferSection mInstanceBuffer;
ConstantBufferSection mPSBuffer0;
};
// This contains various helper functions for building vertices and shader
// inputs for layers.
template <typename Traits>
class BatchRenderPass : public ShaderRenderPass {
public:
BatchRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
: ShaderRenderPass(aBuilder, aItem) {}
protected:
// It is tricky to determine ahead of time whether or not we'll have enough
// room in our buffers to hold all draw commands for a layer, especially
// since layers can have multiple draw rects. We don't want to draw one rect,
// reject the item, then redraw the same rect again in another batch.
// To deal with this we use a transaction approach and reject the transaction
// if we couldn't add everything.
class Txn final {
public:
explicit Txn(BatchRenderPass* aPass)
: mPass(aPass), mPrevInstancePos(aPass->mInstances.GetPosition()) {}
bool Add(const Traits& aTraits) {
if (!AddImpl(aTraits)) {
return Fail();
}
return true;
}
// Add an item based on a draw rect, layer, and optional geometry. This is
// defined in RenderPassMLGPU-inl.h, since it needs access to
// ShaderDefinitionsMLGPU-inl.h.
bool AddImpl(const Traits& aTraits);
bool Fail() {
MOZ_ASSERT(!mStatus.isSome() || !mStatus.value());
mStatus = Some(false);
return false;
}
bool Commit() {
MOZ_ASSERT(!mStatus.isSome() || !mStatus.value());
if (mStatus.isSome()) {
return false;
}
mStatus = Some(true);
return true;
}
~Txn() {
if (!mStatus.isSome() || !mStatus.value()) {
mPass->mInstances.RestorePosition(mPrevInstancePos);
}
}
private:
BatchRenderPass* mPass;
VertexStagingBuffer::Position mPrevVertexPos;
VertexStagingBuffer::Position mPrevItemPos;
ConstantStagingBuffer::Position mPrevInstancePos;
Maybe<bool> mStatus;
};
};
// Shaders which sample from a texture should inherit from this.
class TexturedRenderPass : public BatchRenderPass<TexturedTraits> {
public:
explicit TexturedRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
protected:
struct Info final {
Info(const ItemInfo& aItem, PaintedLayerMLGPU* aLayer);
Info(const ItemInfo& aItem, TexturedLayerMLGPU* aLayer);
Info(const ItemInfo& aItem, ContainerLayerMLGPU* aLayer);
const ItemInfo& item;
gfx::IntSize textureSize;
gfx::Point destOrigin;
Maybe<gfx::Size> scale;
bool decomposeIntoNoRepeatRects;
};
// Add a set of draw rects based on a visible region. The texture size and
// scaling factor are used to compute uv-coordinates.
//
// The origin is the offset from the draw rect to the layer bounds. You can
// also think of it as the translation from layer space into texture space,
// pre-scaling. For example, ImageLayers use the texture bounds as their
// draw rect, so the origin will be (0, 0). ContainerLayer intermediate
// surfaces, on the other hand, are relative to the target offset of the
// layer. In all cases the visible region may be partially occluded, so
// knowing the true origin is important.
template <typename RegionType>
bool AddItems(Txn& aTxn, const Info& aInfo, const RegionType& aDrawRegion) {
for (auto iter = aDrawRegion.RectIter(); !iter.Done(); iter.Next()) {
gfx::Rect drawRect = gfx::Rect(iter.Get().ToUnknownRect());
if (!AddItem(aTxn, aInfo, drawRect)) {
return false;
}
}
return true;
}
private:
// Add a draw instance to the given destination rect. Texture coordinates
// are built from the given texture size, optional scaling factor, and
// texture origin relative to the draw rect. This will ultimately call
// AddClippedItem, potentially clipping the draw rect if needed.
bool AddItem(Txn& aTxn, const Info& aInfo, const gfx::Rect& aDrawRect);
// Add an item that has gone through any necessary clipping already. This
// is the final destination for handling textured items.
bool AddClippedItem(Txn& aTxn, const Info& aInfo, const gfx::Rect& aDrawRect);
protected:
TextureFlags mTextureFlags;
};
// This is only available when MLGDevice::CanUseClearView returns true.
class ClearViewPass final : public RenderPassMLGPU {
public:
ClearViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
bool IsCompatible(const ItemInfo& aItem) override;
void ExecuteRendering() override;
RenderPassType GetType() const override { return RenderPassType::ClearView; }
private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
private:
// Note: Not a RefPtr since this would create a cycle.
RenderViewMLGPU* mView;
gfx::DeviceColor mColor;
nsTArray<gfx::IntRect> mRects;
};
// SolidColorPass is used when ClearViewPass is not available, or when
// the layer has masks, or subpixel or complex transforms.
class SolidColorPass final : public BatchRenderPass<ColorTraits> {
public:
explicit SolidColorPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
RenderPassType GetType() const override { return RenderPassType::SolidColor; }
private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
void SetupPipeline() override;
float GetOpacity() const override;
};
class SingleTexturePass final : public TexturedRenderPass {
public:
explicit SingleTexturePass(FrameBuilder* aBuilder, const ItemInfo& aItem);
RenderPassType GetType() const override {
return RenderPassType::SingleTexture;
}
private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
void SetupPipeline() override;
float GetOpacity() const override { return mOpacity; }
Maybe<MLGBlendState> GetBlendState() const override;
private:
RefPtr<TextureSource> mTexture;
SamplerMode mSamplerMode;
float mOpacity;
};
class ComponentAlphaPass final : public TexturedRenderPass {
public:
explicit ComponentAlphaPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
RenderPassType GetType() const override {
return RenderPassType::ComponentAlpha;
}
private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
void SetupPipeline() override;
float GetOpacity() const override;
Maybe<MLGBlendState> GetBlendState() const override {
return Some(MLGBlendState::ComponentAlpha);
}
private:
float mOpacity;
SamplerMode mSamplerMode;
RefPtr<TextureSource> mTextureOnBlack;
RefPtr<TextureSource> mTextureOnWhite;
};
class VideoRenderPass final : public TexturedRenderPass {
public:
explicit VideoRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
RenderPassType GetType() const override { return RenderPassType::Video; }
private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
void SetupPipeline() override;
float GetOpacity() const override { return mOpacity; }
private:
RefPtr<TextureHost> mHost;
RefPtr<TextureSource> mTexture;
SamplerMode mSamplerMode;
float mOpacity;
};
class RenderViewPass final : public TexturedRenderPass {
public:
RenderViewPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
RenderPassType GetType() const override { return RenderPassType::RenderView; }
private:
bool AddToPass(LayerMLGPU* aItem, ItemInfo& aInfo) override;
void SetupPipeline() override;
bool OnPrepareBuffers() override;
void ExecuteRendering() override;
float GetOpacity() const override;
bool PrepareBlendState();
void RenderWithBackdropCopy();
private:
ConstantBufferSection mBlendConstants;
ContainerLayerMLGPU* mAssignedLayer;
RefPtr<MLGRenderTarget> mSource;
// Note: we don't use RefPtr here since that would cause a cycle. RenderViews
// and RenderPasses are both scoped to the frame anyway.
RenderViewMLGPU* mParentView;
gfx::IntRect mBackdropCopyRect;
Maybe<gfx::CompositionOp> mBlendMode;
};
} // namespace layers
} // namespace mozilla
#endif

View File

@ -1,549 +0,0 @@
/* -*- 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 "RenderViewMLGPU.h"
#include "ContainerLayerMLGPU.h"
#include "FrameBuilder.h"
#include "mozilla/StaticPrefs_layers.h"
#include "LayersHelpers.h"
#include "MLGDevice.h"
#include "RenderPassMLGPU.h"
#include "ShaderDefinitionsMLGPU.h"
#include "Units.h"
#include "UnitTransforms.h"
#include "UtilityMLGPU.h"
namespace mozilla {
namespace layers {
using namespace gfx;
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder,
MLGRenderTarget* aTarget,
const nsIntRegion& aInvalidRegion)
: RenderViewMLGPU(aBuilder, nullptr) {
mTarget = aTarget;
mInvalidBounds = aInvalidRegion.GetBounds();
// The clear region on the layer manager is the area that must be clear after
// we finish drawing.
mPostClearRegion = aBuilder->GetManager()->GetRegionToClear();
// Clamp the post-clear region to the invalid bounds, since clears don't go
// through the scissor rect if using ClearView.
mPostClearRegion.AndWith(mInvalidBounds);
// Since the post-clear will occlude everything, we include it in the final
// opaque area.
mOccludedRegion.OrWith(ViewAs<LayerPixel>(
mPostClearRegion,
PixelCastJustification::RenderTargetIsParentLayerForRoot));
AL_LOG("RenderView %p root with invalid area %s, clear area %s\n", this,
Stringify(mInvalidBounds).c_str(),
Stringify(mPostClearRegion).c_str());
}
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder,
ContainerLayerMLGPU* aContainer,
RenderViewMLGPU* aParent)
: RenderViewMLGPU(aBuilder, aParent) {
mContainer = aContainer;
mTargetOffset = aContainer->GetTargetOffset();
mInvalidBounds = aContainer->GetInvalidRect();
MOZ_ASSERT(!mInvalidBounds.IsEmpty());
AL_LOG("RenderView %p starting with container %p and invalid area %s\n", this,
aContainer->GetLayer(), Stringify(mInvalidBounds).c_str());
mContainer->SetRenderView(this);
}
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder,
RenderViewMLGPU* aParent)
: mBuilder(aBuilder),
mDevice(aBuilder->GetDevice()),
mParent(aParent),
mContainer(nullptr),
mFinishedBuilding(false),
mCurrentLayerBufferIndex(kInvalidResourceIndex),
mCurrentMaskRectBufferIndex(kInvalidResourceIndex),
mCurrentDepthMode(MLGDepthTestMode::Disabled),
mNextSortIndex(1),
mUseDepthBuffer(
StaticPrefs::layers_mlgpu_enable_depth_buffer_AtStartup()),
mDepthBufferNeedsClear(false) {
if (aParent) {
aParent->AddChild(this);
}
}
RenderViewMLGPU::~RenderViewMLGPU() {
for (const auto& child : mChildren) {
child->mParent = nullptr;
}
}
IntSize RenderViewMLGPU::GetSize() const {
MOZ_ASSERT(mFinishedBuilding);
return mTarget->GetSize();
}
MLGRenderTarget* RenderViewMLGPU::GetRenderTarget() const {
MOZ_ASSERT(mFinishedBuilding);
return mTarget;
}
void RenderViewMLGPU::AddChild(RenderViewMLGPU* aParent) {
mChildren.push_back(aParent);
}
void RenderViewMLGPU::Render() {
// We render views depth-first to minimize render target switching.
for (const auto& child : mChildren) {
child->Render();
}
// If the view requires a surface copy (of its backdrop), then we delay
// rendering it until it is added to a batch.
if (mContainer && mContainer->NeedsSurfaceCopy()) {
return;
}
ExecuteRendering();
}
void RenderViewMLGPU::RenderAfterBackdropCopy() {
MOZ_ASSERT(mContainer && mContainer->NeedsSurfaceCopy());
// Update the invalid bounds based on the container's visible region. This
// of course won't affect the prepared pipeline, but it will change the
// scissor rect in SetDeviceState.
mInvalidBounds = mContainer->GetRenderRegion().GetBounds().ToUnknownRect() -
GetTargetOffset();
ExecuteRendering();
}
void RenderViewMLGPU::FinishBuilding() {
MOZ_ASSERT(!mFinishedBuilding);
mFinishedBuilding = true;
if (mContainer) {
MOZ_ASSERT(!mTarget);
MLGRenderTargetFlags flags = MLGRenderTargetFlags::Default;
if (mUseDepthBuffer) {
flags |= MLGRenderTargetFlags::ZBuffer;
}
mTarget = mContainer->UpdateRenderTarget(mDevice, flags);
}
}
void RenderViewMLGPU::AddItem(LayerMLGPU* aItem, const IntRect& aRect,
Maybe<Polygon>&& aGeometry) {
AL_LOG("RenderView %p analyzing layer %p\n", this, aItem->GetLayer());
// If the item is not visible at all, skip it.
if (aItem->GetComputedOpacity() == 0.0f) {
AL_LOG("RenderView %p culling item %p with no opacity\n", this,
aItem->GetLayer());
return;
}
// When using the depth buffer, the z-index for items is important.
//
// Sort order starts at 1 and goes to positive infinity, with smaller values
// being closer to the screen. Our viewport is the same, with anything
// outside of [0.0, 1.0] being culled, and lower values occluding higher
// values. To make this work our projection transform scales the z-axis.
// Note that we do not use 0 as a sorting index (when depth-testing is
// enabled) because this would result in a z-value of 1.0, which would be
// culled.
ItemInfo info(mBuilder, this, aItem, mNextSortIndex++, aRect,
std::move(aGeometry));
// If the item is not visible, or we can't add it to the layer constant
// buffer for some reason, bail out.
if (!UpdateVisibleRegion(info) || !mBuilder->AddLayerToConstantBuffer(info)) {
AL_LOG("RenderView %p culled item %p!\n", this, aItem->GetLayer());
return;
}
// We support all layer types now.
MOZ_ASSERT(info.type != RenderPassType::Unknown);
if (info.renderOrder == RenderOrder::FrontToBack) {
AddItemFrontToBack(aItem, info);
} else {
AddItemBackToFront(aItem, info);
}
}
bool RenderViewMLGPU::UpdateVisibleRegion(ItemInfo& aItem) {
// If the item has some kind of complex transform, we perform a very
// simple occlusion test and move on. We using a depth buffer we skip
// CPU-based occlusion culling as well, since the GPU will do most of our
// culling work for us.
if (mUseDepthBuffer || !aItem.translation ||
!StaticPrefs::layers_mlgpu_enable_cpu_occlusion_AtStartup()) {
// Update the render region even if we won't compute visibility, since some
// layer types (like Canvas and Image) need to have the visible region
// clamped.
LayerIntRegion region = aItem.layer->GetShadowVisibleRegion();
aItem.layer->SetRenderRegion(std::move(region));
AL_LOG("RenderView %p simple occlusion test, bounds=%s, translation?=%d\n",
this, Stringify(aItem.bounds).c_str(), aItem.translation ? 1 : 0);
return mInvalidBounds.Intersects(aItem.bounds);
}
MOZ_ASSERT(aItem.rectilinear);
AL_LOG("RenderView %p starting visibility tests:\n", this);
AL_LOG(" occluded=%s\n", Stringify(mOccludedRegion).c_str());
// Compute the translation into render target space.
LayerIntPoint translation = LayerIntPoint::FromUnknownPoint(
aItem.translation.value() - mTargetOffset);
AL_LOG(" translation=%s\n", Stringify(translation).c_str());
IntRect clip = aItem.layer->GetComputedClipRect().ToUnknownRect();
AL_LOG(" clip=%s\n", Stringify(translation).c_str());
LayerIntRegion region = aItem.layer->GetShadowVisibleRegion();
region.MoveBy(translation);
AL_LOG(" effective-visible=%s\n", Stringify(region).c_str());
region.SubOut(mOccludedRegion);
region.AndWith(LayerIntRect::FromUnknownRect(mInvalidBounds));
region.AndWith(LayerIntRect::FromUnknownRect(clip));
if (region.IsEmpty()) {
return false;
}
// Move the visible region back into layer space.
region.MoveBy(-translation);
AL_LOG(" new-local-visible=%s\n", Stringify(region).c_str());
aItem.layer->SetRenderRegion(std::move(region));
// Apply the new occluded area. We do another dance with the translation to
// avoid copying the region. We do this after the SetRegionToRender call to
// accomodate the possiblity of a layer changing its visible region.
if (aItem.opaque) {
mOccludedRegion.MoveBy(-translation);
mOccludedRegion.OrWith(aItem.layer->GetRenderRegion());
mOccludedRegion.MoveBy(translation);
AL_LOG(" new-occluded=%s\n", Stringify(mOccludedRegion).c_str());
// If the occluded region gets too complicated, we reset it.
if (mOccludedRegion.GetNumRects() >= 32) {
mOccludedRegion.SetEmpty();
AL_LOG(" clear-occluded, too many rects\n");
}
}
return true;
}
void RenderViewMLGPU::AddItemFrontToBack(LayerMLGPU* aLayer, ItemInfo& aItem) {
// We receive items in front-to-back order. Ideally we want to push items
// as far back into batches impossible, to ensure the GPU can do a good
// job at culling. However we also want to make sure we actually batch
// items versus drawing one primitive per pass.
//
// As a compromise we look at the most 3 recent batches and then give up.
// This can be tweaked in the future.
static const size_t kMaxSearch = 3;
size_t iterations = 0;
for (auto iter = mFrontToBack.rbegin(); iter != mFrontToBack.rend(); iter++) {
RenderPassMLGPU* pass = (*iter);
if (pass->IsCompatible(aItem) && pass->AcceptItem(aItem)) {
AL_LOG("RenderView %p added layer %p to pass %p (%d)\n", this,
aLayer->GetLayer(), pass, int(pass->GetType()));
return;
}
if (++iterations > kMaxSearch) {
break;
}
}
RefPtr<RenderPassMLGPU> pass = RenderPassMLGPU::CreatePass(mBuilder, aItem);
if (!pass || !pass->AcceptItem(aItem)) {
MOZ_ASSERT_UNREACHABLE("Could not build a pass for item!");
return;
}
AL_LOG("RenderView %p added layer %p to new pass %p (%d)\n", this,
aLayer->GetLayer(), pass.get(), int(pass->GetType()));
mFrontToBack.push_back(pass);
}
void RenderViewMLGPU::AddItemBackToFront(LayerMLGPU* aLayer, ItemInfo& aItem) {
// We receive layers in front-to-back order, but there are two cases when we
// actually draw back-to-front: when the depth buffer is disabled, or when
// using the depth buffer and the item has transparent pixels (and therefore
// requires blending). In these cases we will build vertex and constant
// buffers in reverse, as well as execute batches in reverse, to ensure the
// correct ordering.
//
// Note: We limit the number of batches we search through, since it's better
// to add new draw calls than spend too much time finding compatible
// batches further down.
static const size_t kMaxSearch = 10;
size_t iterations = 0;
for (auto iter = mBackToFront.begin(); iter != mBackToFront.end(); iter++) {
RenderPassMLGPU* pass = (*iter);
if (pass->IsCompatible(aItem) && pass->AcceptItem(aItem)) {
AL_LOG("RenderView %p added layer %p to pass %p (%d)\n", this,
aLayer->GetLayer(), pass, int(pass->GetType()));
return;
}
if (pass->Intersects(aItem)) {
break;
}
if (++iterations > kMaxSearch) {
break;
}
}
RefPtr<RenderPassMLGPU> pass = RenderPassMLGPU::CreatePass(mBuilder, aItem);
if (!pass || !pass->AcceptItem(aItem)) {
MOZ_ASSERT_UNREACHABLE("Could not build a pass for item!");
return;
}
AL_LOG("RenderView %p added layer %p to new pass %p (%d)\n", this,
aLayer->GetLayer(), pass.get(), int(pass->GetType()));
mBackToFront.push_front(pass);
}
void RenderViewMLGPU::Prepare() {
if (!mTarget) {
return;
}
// Prepare front-to-back passes. These are only present when using the depth
// buffer, and they contain only opaque data.
for (RefPtr<RenderPassMLGPU>& pass : mFrontToBack) {
pass->PrepareForRendering();
}
// Prepare the Clear buffer, which will fill the render target with
// transparent pixels. This must happen before we set up world constants,
// since it can create new z-indices.
PrepareClears();
// Prepare the world constant buffer. This must be called after we've
// finished allocating all z-indices.
{
WorldConstants vsConstants;
Matrix4x4 projection = Matrix4x4::Translation(-1.0, 1.0, 0.0);
projection.PreScale(2.0 / float(mTarget->GetSize().width),
2.0 / float(mTarget->GetSize().height), 1.0f);
projection.PreScale(1.0f, -1.0f, 1.0f);
memcpy(vsConstants.projection, &projection._11, 64);
vsConstants.targetOffset = Point(mTargetOffset);
vsConstants.sortIndexOffset = PrepareDepthBuffer();
vsConstants.debugFrameNumber =
mBuilder->GetManager()->GetDebugFrameNumber();
SharedConstantBuffer* shared = mDevice->GetSharedVSBuffer();
if (!shared->Allocate(&mWorldConstants, vsConstants)) {
return;
}
}
// Prepare back-to-front passes. In depth buffer mode, these contain draw
// calls that might produce transparent pixels. When using CPU-based occlusion
// culling, all draw calls are back-to-front.
for (RefPtr<RenderPassMLGPU>& pass : mBackToFront) {
pass->PrepareForRendering();
}
// Now, process children.
for (const auto& iter : mChildren) {
iter->Prepare();
}
}
void RenderViewMLGPU::ExecuteRendering() {
if (!mTarget) {
return;
}
if (!mWorldConstants.IsValid()) {
gfxWarning() << "Failed to allocate constant buffer for world transform";
return;
}
SetDeviceState();
// If using the depth buffer, clear it (if needed) and enable writes.
if (mUseDepthBuffer) {
if (mDepthBufferNeedsClear) {
mDevice->ClearDepthBuffer(mTarget);
}
SetDepthTestMode(MLGDepthTestMode::Write);
}
// Opaque items, rendered front-to-back.
for (auto iter = mFrontToBack.begin(); iter != mFrontToBack.end(); iter++) {
ExecutePass(*iter);
}
if (mUseDepthBuffer) {
// From now on we might be rendering transparent pixels, so we disable
// writing to the z-buffer.
SetDepthTestMode(MLGDepthTestMode::ReadOnly);
}
// Clear any pixels that are not occluded, and therefore might require
// blending.
mDevice->DrawClearRegion(mPreClear);
// Render back-to-front passes.
for (auto iter = mBackToFront.begin(); iter != mBackToFront.end(); iter++) {
ExecutePass(*iter);
}
// Make sure the post-clear area has no pixels.
if (!mPostClearRegion.IsEmpty()) {
mDevice->DrawClearRegion(mPostClear);
}
// We repaint the entire invalid region, even if it is partially occluded.
// Thus it's safe for us to clear the invalid area here. If we ever switch
// to nsIntRegions, we will have to take the difference between the paitned
// area and the invalid area.
if (mContainer) {
mContainer->ClearInvalidRect();
}
}
void RenderViewMLGPU::ExecutePass(RenderPassMLGPU* aPass) {
if (!aPass->IsPrepared()) {
return;
}
// Change the layer buffer if needed.
if (aPass->GetLayerBufferIndex() != mCurrentLayerBufferIndex) {
mCurrentLayerBufferIndex = aPass->GetLayerBufferIndex();
ConstantBufferSection section =
mBuilder->GetLayerBufferByIndex(mCurrentLayerBufferIndex);
mDevice->SetVSConstantBuffer(kLayerBufferSlot, &section);
}
// Change the mask rect buffer if needed.
if (aPass->GetMaskRectBufferIndex() &&
aPass->GetMaskRectBufferIndex().value() != mCurrentMaskRectBufferIndex) {
mCurrentMaskRectBufferIndex = aPass->GetMaskRectBufferIndex().value();
ConstantBufferSection section =
mBuilder->GetMaskRectBufferByIndex(mCurrentMaskRectBufferIndex);
mDevice->SetVSConstantBuffer(kMaskBufferSlot, &section);
}
aPass->ExecuteRendering();
}
void RenderViewMLGPU::SetDeviceState() {
// Note: we unbind slot 0 (which is where the render target could have been
// bound on a previous frame). Otherwise we trigger
// D3D11_DEVICE_PSSETSHADERRESOURCES_HAZARD.
mDevice->UnsetPSTexture(0);
mDevice->SetRenderTarget(mTarget);
mDevice->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
mDevice->SetScissorRect(Some(mInvalidBounds));
mDevice->SetVSConstantBuffer(kWorldConstantBufferSlot, &mWorldConstants);
}
void RenderViewMLGPU::SetDepthTestMode(MLGDepthTestMode aMode) {
mDevice->SetDepthTestMode(aMode);
mCurrentDepthMode = aMode;
}
void RenderViewMLGPU::RestoreDeviceState() {
SetDeviceState();
mDevice->SetDepthTestMode(mCurrentDepthMode);
mCurrentLayerBufferIndex = kInvalidResourceIndex;
mCurrentMaskRectBufferIndex = kInvalidResourceIndex;
}
int32_t RenderViewMLGPU::PrepareDepthBuffer() {
if (!mUseDepthBuffer) {
return 0;
}
// Rather than clear the depth buffer every frame, we offset z-indices each
// frame, starting with indices far away from the screen and moving toward
// the user each successive frame. This ensures that frames can re-use the
// depth buffer but never collide with previously written values.
//
// Once a frame runs out of sort indices, we finally clear the depth buffer
// and start over again.
// Note: the lowest sort index (kDepthLimit) is always occluded since it will
// resolve to the clear value - kDepthLimit / kDepthLimit == 1.0.
//
// If we don't have any more indices to allocate, we need to clear the depth
// buffer and start fresh.
int32_t highestIndex = mTarget->GetLastDepthStart();
if (highestIndex < mNextSortIndex) {
mDepthBufferNeedsClear = true;
highestIndex = kDepthLimit;
}
// We should not have more than kDepthLimit layers to draw. The last known
// sort index might appear in the depth buffer and occlude something, so
// we subtract 1. This ensures all our indices will compare less than all
// old indices.
int32_t sortOffset = highestIndex - mNextSortIndex - 1;
MOZ_ASSERT(sortOffset >= 0);
mTarget->SetLastDepthStart(sortOffset);
return sortOffset;
}
void RenderViewMLGPU::PrepareClears() {
// We don't do any clearing if we're copying from a source backdrop.
if (mContainer && mContainer->NeedsSurfaceCopy()) {
return;
}
// Get the list of rects to clear. If using the depth buffer, we don't
// care if it's accurate since the GPU will do occlusion testing for us.
// If not using the depth buffer, we subtract out the occluded region.
LayerIntRegion region = LayerIntRect::FromUnknownRect(mInvalidBounds);
if (!mUseDepthBuffer) {
// Don't let the clear region become too complicated.
region.SubOut(mOccludedRegion);
region.SimplifyOutward(kMaxClearViewRects);
}
Maybe<int32_t> sortIndex;
if (mUseDepthBuffer) {
// Note that we use the lowest available sorting index, to ensure that when
// using the z-buffer, we don't draw over already-drawn content.
sortIndex = Some(mNextSortIndex++);
}
nsTArray<IntRect> rects = ToRectArray(region);
mDevice->PrepareClearRegion(&mPreClear, std::move(rects), sortIndex);
if (!mPostClearRegion.IsEmpty()) {
// Prepare the final clear as well. Note that we always do this clear at the
// very end, even when the depth buffer is enabled, so we don't bother
// setting a useful sorting index. If and when we try to ship the depth
// buffer, we would execute this clear earlier in the pipeline and give it
// the closest possible z-ordering to the screen.
nsTArray<IntRect> rects = ToRectArray(mPostClearRegion);
mDevice->PrepareClearRegion(&mPostClear, std::move(rects), Nothing());
}
}
} // namespace layers
} // namespace mozilla

View File

@ -1,136 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_RenderViewMLGPU_h
#define mozilla_gfx_layers_mlgpu_RenderViewMLGPU_h
#include "LayerManagerMLGPU.h"
#include "ClearRegionHelper.h"
#include "RenderPassMLGPU.h"
#include "Units.h"
#include <deque>
namespace mozilla {
namespace layers {
class FrameBuilder;
class ContainerLayerMLGPU;
class MLGRenderTarget;
class RenderViewMLGPU {
public:
NS_INLINE_DECL_REFCOUNTING(RenderViewMLGPU)
// Constructor for the widget render target.
RenderViewMLGPU(FrameBuilder* aBuilder, MLGRenderTarget* aTarget,
const nsIntRegion& aInvalidRegion);
// Constructor for intermediate surfaces.
RenderViewMLGPU(FrameBuilder* aBuilder, ContainerLayerMLGPU* aContainer,
RenderViewMLGPU* aParent);
void Prepare();
void Render();
void AddChild(RenderViewMLGPU* aParent);
void AddItem(LayerMLGPU* aItem, const gfx::IntRect& aBounds,
Maybe<gfx::Polygon>&& aGeometry);
void FinishBuilding();
const gfx::IntPoint& GetTargetOffset() const { return mTargetOffset; }
RenderViewMLGPU* GetParent() const { return mParent; }
bool HasDepthBuffer() const { return mUseDepthBuffer; }
// Render after having previously delayed rendering due to the view
// requiring a backdrop copy.
void RenderAfterBackdropCopy();
void RestoreDeviceState();
// The size and render target cannot be read until the view has finished
// building, since we try to right-size the render target to the visible
// region.
MLGRenderTarget* GetRenderTarget() const;
gfx::IntSize GetSize() const;
gfx::IntRect GetInvalidRect() const { return mInvalidBounds; }
private:
RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParent);
~RenderViewMLGPU();
void ExecuteRendering();
bool UpdateVisibleRegion(ItemInfo& aItem);
void AddItemFrontToBack(LayerMLGPU* aLayer, ItemInfo& aItem);
void AddItemBackToFront(LayerMLGPU* aLayer, ItemInfo& aItem);
void PrepareClears();
void SetDeviceState();
void SetDepthTestMode(MLGDepthTestMode aMode);
void ExecutePass(RenderPassMLGPU* aPass);
// Return the sorting index offset to use.
int32_t PrepareDepthBuffer();
private:
std::deque<RefPtr<RenderPassMLGPU>> mFrontToBack;
std::deque<RefPtr<RenderPassMLGPU>> mBackToFront;
FrameBuilder* mBuilder;
RefPtr<MLGDevice> mDevice;
RenderViewMLGPU* mParent;
std::vector<RefPtr<RenderViewMLGPU>> mChildren;
// Shader data.
ConstantBufferSection mWorldConstants;
// Information for the initial target surface clear. This covers the area that
// won't be occluded by opaque content.
ClearRegionHelper mPreClear;
// The post-clear region, that must be cleared after all drawing is done.
nsIntRegion mPostClearRegion;
ClearRegionHelper mPostClear;
// Either an MLGSwapChain-derived render target, or an intermediate surface.
RefPtr<MLGRenderTarget> mTarget;
// For intermediate render targets only, this is the layer owning the render
// target.
ContainerLayerMLGPU* mContainer;
// The offset adjustment from container layer space to render target space.
// This is 0,0 for the root view.
gfx::IntPoint mTargetOffset;
// The invalid bounds as computed by LayerTreeInvalidation. This is the
// initial render bounds size, if invalidation is disabled.
gfx::IntRect mInvalidBounds;
// The occluded region, which is updated every time we process an opaque,
// rectangular item. This is not actually in LayerPixels, we do this to
// avoid FromUnknownRegion which has array copies.
LayerIntRegion mOccludedRegion;
// True if we've finished adding layers to the view.
bool mFinishedBuilding;
// This state is used to avoid changing buffers while we execute batches.
size_t mCurrentLayerBufferIndex;
size_t mCurrentMaskRectBufferIndex;
// This state is saved locally so it can be restored in RestoreDeviceState.
MLGDepthTestMode mCurrentDepthMode;
// Depth-buffer tracking.
int32_t mNextSortIndex;
bool mUseDepthBuffer;
bool mDepthBufferNeedsClear;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_RenderViewMLGPU_h

View File

@ -1,79 +0,0 @@
/* -*- 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 _include_gfx_layers_mlgpu_ShaderDefinitions_inl_h
#define _include_gfx_layers_mlgpu_ShaderDefinitions_inl_h
namespace mozilla {
namespace layers {
namespace mlg {
inline const Maybe<gfx::Polygon>& SimpleTraits::geometry() const {
return mItem.geometry;
}
inline nsTArray<gfx::Triangle> SimpleTraits::GenerateTriangles(
const gfx::Polygon& aPolygon) const {
return aPolygon.ToTriangles();
}
inline SimpleTraits::TriangleVertices SimpleTraits::MakeVertex(
const FirstTriangle& aIgnore) const {
TriangleVertices v = {mRect.BottomLeft(), mRect.TopLeft(), mRect.TopRight(),
mItem.layerIndex, mItem.sortOrder};
return v;
}
inline SimpleTraits::TriangleVertices SimpleTraits::MakeVertex(
const SecondTriangle& aIgnore) const {
TriangleVertices v = {mRect.TopRight(), mRect.BottomRight(),
mRect.BottomLeft(), mItem.layerIndex, mItem.sortOrder};
return v;
}
inline SimpleTraits::TriangleVertices SimpleTraits::MakeVertex(
const gfx::Triangle& aTriangle) const {
TriangleVertices v = {aTriangle.p1, aTriangle.p2, aTriangle.p3,
mItem.layerIndex, mItem.sortOrder};
return v;
}
inline SimpleTraits::UnitQuadVertex SimpleTraits::MakeUnitQuadVertex() const {
UnitQuadVertex v = {mRect, mItem.layerIndex, mItem.sortOrder};
return v;
}
inline nsTArray<gfx::TexturedTriangle> TexturedTraits::GenerateTriangles(
const gfx::Polygon& aPolygon) const {
return GenerateTexturedTriangles(aPolygon, mRect, mTexCoords);
}
inline TexturedTraits::VertexData TexturedTraits::MakeVertexData(
const FirstTriangle& aIgnore) const {
VertexData v = {mTexCoords.BottomLeft(), mTexCoords.TopLeft(),
mTexCoords.TopRight()};
return v;
}
inline TexturedTraits::VertexData TexturedTraits::MakeVertexData(
const SecondTriangle& aIgnore) const {
VertexData v = {mTexCoords.TopRight(), mTexCoords.BottomRight(),
mTexCoords.BottomLeft()};
return v;
}
inline TexturedTraits::VertexData TexturedTraits::MakeVertexData(
const gfx::TexturedTriangle& aTriangle) const {
VertexData v = {aTriangle.textureCoords.p1, aTriangle.textureCoords.p2,
aTriangle.textureCoords.p3};
return v;
}
} // namespace mlg
} // namespace layers
} // namespace mozilla
#endif // _include_gfx_layers_mlgpu_ShaderDefinitions_inl_h

View File

@ -1,195 +0,0 @@
/* -*- 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_GFX_SHADERDEFINITIONSMLGPU_H
#define MOZILLA_GFX_SHADERDEFINITIONSMLGPU_H
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Triangle.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/LayersHelpers.h"
#include "nsTArray.h"
namespace mozilla {
namespace layers {
struct ItemInfo;
class ShaderRenderPass;
namespace mlg {
// These may need to move into run-time values determined by MLGDevice.
static const size_t kConstantBufferElementSize = 16;
static const size_t kMaxConstantBufferSize = 4096 * kConstantBufferElementSize;
// Vertex shader slots. We reverse the first two slots across all shaders,
// and the first three slots free across all RenderPass shaders, for
// uniformity.
static const uint32_t kWorldConstantBufferSlot = 0;
static const uint32_t kLayerBufferSlot = 1;
static const uint32_t kMaskBufferSlot = 3;
static const uint32_t kBlendConstantBufferSlot = 4;
static const uint32_t kClearConstantBufferSlot = 2;
// This is specified in common-ps.hlsl.
static const uint32_t kMaskLayerTextureSlot = 4;
static const uint32_t kDefaultSamplerSlot = 0;
static const uint32_t kMaskSamplerSlot = 1;
// These are the maximum slot numbers we bind. We assert that no binding
// happens above the max slot, since we try to clear buffer bindings at
// the end of each frame.
static const uint32_t kMaxVertexShaderConstantBuffers = 5;
static const uint32_t kMaxPixelShaderConstantBuffers = 3;
// Maximum depth in the depth buffer. This must match common-vs.hlsl.
static const int32_t kDepthLimit = 1000000;
struct WorldConstants {
float projection[4][4];
gfx::Point targetOffset;
int sortIndexOffset;
unsigned debugFrameNumber;
};
struct ClearConstants {
explicit ClearConstants(int aDepth) : depth(aDepth) {}
int depth;
int padding[3];
};
struct LayerConstants {
float transform[4][4];
gfx::Rect clipRect;
uint32_t maskIndex;
uint32_t padding[3];
};
struct MaskCombineInput {
float texCoords[4];
};
struct MaskInformation {
MaskInformation(float aOpacity, bool aHasMask)
: opacity(aOpacity), hasMask(aHasMask ? 1 : 0) {}
float opacity;
uint32_t hasMask;
uint32_t padding[2];
};
struct YCbCrShaderConstants {
float yuvColorMatrix[3][4];
};
struct YCbCrColorDepthConstants {
float coefficient;
uint32_t padding[3];
};
struct BlendVertexShaderConstants {
float backdropTransform[4][4];
};
template <typename T>
static inline nsTArray<gfx::IntRect> ToRectArray(const T& aRegion) {
nsTArray<gfx::IntRect> rects;
for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
rects.AppendElement(iter.Get().ToUnknownRect());
}
return rects;
}
struct SimpleTraits {
SimpleTraits(const ItemInfo& aItem, const gfx::Rect& aRect)
: mItem(aItem), mRect(aRect) {}
// Helper nonce structs so functions can break vertex data up by each
// triangle in a quad, or return vertex info for a unit quad.
struct AnyTriangle {};
struct FirstTriangle : AnyTriangle {};
struct SecondTriangle : AnyTriangle {};
struct UnitQuad {};
// This is the base vertex layout used by all unit quad shaders.
struct UnitQuadVertex {
gfx::Rect rect;
uint32_t layerIndex;
int depth;
};
// This is the base vertex layout used by all unit triangle shaders.
struct TriangleVertices {
gfx::Point p1, p2, p3;
uint32_t layerIndex;
int depth;
};
// Helper functions for populating a TriangleVertices. The first two use mRect
// to generate triangles, the third function uses coordinates from an already
// computed triangle.
TriangleVertices MakeVertex(const FirstTriangle& aIgnore) const;
TriangleVertices MakeVertex(const SecondTriangle& aIgnore) const;
TriangleVertices MakeVertex(const gfx::Triangle& aTriangle) const;
UnitQuadVertex MakeUnitQuadVertex() const;
// This default GenerateTriangles only computes the 3 points of each triangle
// in the polygon. If needed, shaders can override this and return a more
// complex triangle, to encode dependent information in extended vertex data.
//
// AddShaderVertices will deduce this return type. It should be an nsTArray<T>
// where T inherits from Triangle.
nsTArray<gfx::Triangle> GenerateTriangles(const gfx::Polygon& aPolygon) const;
// Accessors.
const Maybe<gfx::Polygon>& geometry() const;
const gfx::Rect& rect() const { return mRect; }
const ItemInfo& mItem;
gfx::Rect mRect;
};
struct ColorTraits : public SimpleTraits {
ColorTraits(const ItemInfo& aItem, const gfx::Rect& aRect,
const gfx::DeviceColor& aColor)
: SimpleTraits(aItem, aRect), mColor(aColor) {}
// Color data is the same across all vertex types.
template <typename VertexType>
const gfx::DeviceColor& MakeVertexData(const VertexType& aIgnore) const {
return mColor;
}
gfx::DeviceColor mColor;
};
struct TexturedTraits : public SimpleTraits {
TexturedTraits(const ItemInfo& aItem, const gfx::Rect& aRect,
const gfx::Rect& aTexCoords)
: SimpleTraits(aItem, aRect), mTexCoords(aTexCoords) {}
// Textured triangles need to compute a texture coordinate for each vertex.
nsTArray<gfx::TexturedTriangle> GenerateTriangles(
const gfx::Polygon& aPolygon) const;
struct VertexData {
gfx::Point p1, p2, p3;
};
VertexData MakeVertexData(const FirstTriangle& aIgnore) const;
VertexData MakeVertexData(const SecondTriangle& aIgnore) const;
VertexData MakeVertexData(const gfx::TexturedTriangle& aTriangle) const;
const gfx::Rect& MakeVertexData(const UnitQuad& aIgnore) const {
return mTexCoords;
}
gfx::Rect mTexCoords;
};
} // namespace mlg
} // namespace layers
} // namespace mozilla
#endif

View File

@ -1,275 +0,0 @@
/* -*- 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 "SharedBufferMLGPU.h"
#include "BufferCache.h"
#include "MLGDevice.h"
namespace mozilla {
namespace layers {
SharedBufferMLGPU::SharedBufferMLGPU(MLGDevice* aDevice, MLGBufferType aType,
size_t aDefaultSize)
: mDevice(aDevice),
mType(aType),
mDefaultSize(aDefaultSize),
mCanUseOffsetAllocation(true),
mCurrentPosition(0),
mMaxSize(0),
mMap(),
mMapped(false),
mBytesUsedThisFrame(0),
mNumSmallFrames(0) {
MOZ_COUNT_CTOR(SharedBufferMLGPU);
}
SharedBufferMLGPU::~SharedBufferMLGPU() {
MOZ_COUNT_DTOR(SharedBufferMLGPU);
Unmap();
}
bool SharedBufferMLGPU::Init() {
// If we can't use buffer offset binding, we never allocated shared buffers.
if (!mCanUseOffsetAllocation) {
return true;
}
// If we can use offset binding, allocate an initial shared buffer now.
if (!GrowBuffer(mDefaultSize)) {
return false;
}
return true;
}
void SharedBufferMLGPU::Reset() {
// We shouldn't be mapped here, but just in case, unmap now.
Unmap();
mBytesUsedThisFrame = 0;
// If we allocated a large buffer for a particularly heavy layer tree,
// but have not used most of the buffer again for many frames, we
// discard the buffer. This is to prevent having to perform large
// pointless uploads after visiting a single havy page - it also
// lessens ping-ponging between large and small buffers.
if (mBuffer && (mBuffer->GetSize() > mDefaultSize * 4) &&
mNumSmallFrames >= 10) {
mBuffer = nullptr;
}
// Note that we do not aggressively map a new buffer. There's no reason to,
// and it'd cause unnecessary uploads when painting empty frames.
}
bool SharedBufferMLGPU::EnsureMappedBuffer(size_t aBytes) {
if (!mBuffer || (mMaxSize - mCurrentPosition < aBytes)) {
if (!GrowBuffer(aBytes)) {
return false;
}
}
if (!mMapped && !Map()) {
return false;
}
return true;
}
// We don't want to cache large buffers, since it results in larger uploads
// that might not be needed.
static const size_t kMaxCachedBufferSize = 128 * 1024;
bool SharedBufferMLGPU::GrowBuffer(size_t aBytes) {
// We only pre-allocate buffers if we can use offset allocation.
MOZ_ASSERT(mCanUseOffsetAllocation);
// Unmap the previous buffer. This will retain mBuffer, but free up the
// address space used by its mapping.
Unmap();
size_t maybeSize = mDefaultSize;
if (mBuffer) {
// Try to first grow the previous allocation size.
maybeSize = std::min(kMaxCachedBufferSize, mBuffer->GetSize() * 2);
}
size_t bytes = std::max(aBytes, maybeSize);
mBuffer = mDevice->CreateBuffer(mType, bytes, MLGUsage::Dynamic);
if (!mBuffer) {
return false;
}
mCurrentPosition = 0;
mMaxSize = mBuffer->GetSize();
return true;
}
void SharedBufferMLGPU::PrepareForUsage() {
Unmap();
if (mBytesUsedThisFrame <= mDefaultSize) {
mNumSmallFrames++;
} else {
mNumSmallFrames = 0;
}
}
bool SharedBufferMLGPU::Map() {
MOZ_ASSERT(mBuffer);
MOZ_ASSERT(!mMapped);
if (!mDevice->Map(mBuffer, MLGMapType::WRITE_DISCARD, &mMap)) {
// Don't retain the buffer, it's useless if we can't map it.
mBuffer = nullptr;
return false;
}
mCurrentPosition = 0;
mMapped = true;
return true;
}
void SharedBufferMLGPU::Unmap() {
if (!mMapped) {
return;
}
mBytesUsedThisFrame += mCurrentPosition;
mDevice->Unmap(mBuffer);
mMap = MLGMappedResource();
mMapped = false;
}
uint8_t* SharedBufferMLGPU::GetBufferPointer(size_t aBytes,
ptrdiff_t* aOutOffset,
RefPtr<MLGBuffer>* aOutBuffer) {
if (!EnsureMappedBuffer(aBytes)) {
return nullptr;
}
ptrdiff_t newPos = mCurrentPosition + aBytes;
MOZ_ASSERT(size_t(newPos) <= mMaxSize);
*aOutOffset = mCurrentPosition;
*aOutBuffer = mBuffer;
uint8_t* ptr = reinterpret_cast<uint8_t*>(mMap.mData) + mCurrentPosition;
mCurrentPosition = newPos;
return ptr;
}
VertexBufferSection::VertexBufferSection()
: mOffset(-1), mNumVertices(0), mStride(0) {}
void VertexBufferSection::Init(MLGBuffer* aBuffer, ptrdiff_t aOffset,
size_t aNumVertices, size_t aStride) {
mBuffer = aBuffer;
mOffset = aOffset;
mNumVertices = aNumVertices;
mStride = aStride;
}
ConstantBufferSection::ConstantBufferSection()
: mOffset(-1), mNumBytes(0), mNumItems(0) {}
void ConstantBufferSection::Init(MLGBuffer* aBuffer, ptrdiff_t aOffset,
size_t aBytes, size_t aNumItems) {
mBuffer = aBuffer;
mOffset = aOffset;
mNumBytes = aBytes;
mNumItems = aNumItems;
}
SharedVertexBuffer::SharedVertexBuffer(MLGDevice* aDevice, size_t aDefaultSize)
: SharedBufferMLGPU(aDevice, MLGBufferType::Vertex, aDefaultSize) {}
bool SharedVertexBuffer::Allocate(VertexBufferSection* aHolder,
size_t aNumItems, size_t aSizeOfItem,
const void* aData) {
RefPtr<MLGBuffer> buffer;
ptrdiff_t offset;
size_t bytes = aSizeOfItem * aNumItems;
uint8_t* ptr = GetBufferPointer(bytes, &offset, &buffer);
if (!ptr) {
return false;
}
memcpy(ptr, aData, bytes);
aHolder->Init(buffer, offset, aNumItems, aSizeOfItem);
return true;
}
AutoBufferUploadBase::AutoBufferUploadBase() : mPtr(nullptr) {}
AutoBufferUploadBase::~AutoBufferUploadBase() {
if (mBuffer) {
UnmapBuffer();
}
}
void AutoBufferUploadBase::Init(void* aPtr, MLGDevice* aDevice,
MLGBuffer* aBuffer) {
MOZ_ASSERT(!mPtr && aPtr);
mPtr = aPtr;
mDevice = aDevice;
mBuffer = aBuffer;
}
SharedConstantBuffer::SharedConstantBuffer(MLGDevice* aDevice,
size_t aDefaultSize)
: SharedBufferMLGPU(aDevice, MLGBufferType::Constant, aDefaultSize) {
mMaxConstantBufferBindSize = aDevice->GetMaxConstantBufferBindSize();
mCanUseOffsetAllocation = aDevice->CanUseConstantBufferOffsetBinding();
}
bool SharedConstantBuffer::Allocate(ConstantBufferSection* aHolder,
AutoBufferUploadBase* aPtr,
size_t aNumItems, size_t aSizeOfItem) {
MOZ_ASSERT(aSizeOfItem % 16 == 0, "Items must be padded to 16 bytes");
size_t bytes = aNumItems * aSizeOfItem;
if (bytes > mMaxConstantBufferBindSize) {
gfxWarning()
<< "Attempted to allocate too many bytes into a constant buffer";
return false;
}
RefPtr<MLGBuffer> buffer;
ptrdiff_t offset;
if (!GetBufferPointer(aPtr, bytes, &offset, &buffer)) {
return false;
}
aHolder->Init(buffer, offset, bytes, aNumItems);
return true;
}
uint8_t* SharedConstantBuffer::AllocateNewBuffer(
size_t aBytes, ptrdiff_t* aOutOffset, RefPtr<MLGBuffer>* aOutBuffer) {
RefPtr<MLGBuffer> buffer;
if (BufferCache* cache = mDevice->GetConstantBufferCache()) {
buffer = cache->GetOrCreateBuffer(aBytes);
} else {
buffer = mDevice->CreateBuffer(MLGBufferType::Constant, aBytes,
MLGUsage::Dynamic);
}
if (!buffer) {
return nullptr;
}
MLGMappedResource map;
if (!mDevice->Map(buffer, MLGMapType::WRITE_DISCARD, &map)) {
return nullptr;
}
// Signal that offsetting is not supported.
*aOutOffset = -1;
*aOutBuffer = buffer;
return reinterpret_cast<uint8_t*>(map.mData);
}
void AutoBufferUploadBase::UnmapBuffer() { mDevice->Unmap(mBuffer); }
} // namespace layers
} // namespace mozilla

View File

@ -1,273 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_SharedBufferMLGPU_h
#define mozilla_gfx_layers_mlgpu_SharedBufferMLGPU_h
#include "ShaderDefinitionsMLGPU.h"
#include "MLGDevice.h"
#include "MLGDeviceTypes.h"
#include "StagingBuffer.h"
#include "mozilla/gfx/Logging.h"
namespace mozilla {
namespace layers {
class MLGBuffer;
class SharedBufferMLGPU {
public:
virtual ~SharedBufferMLGPU();
bool Init();
// Call before starting a new frame.
void Reset();
// Call to finish any pending uploads.
void PrepareForUsage();
protected:
SharedBufferMLGPU(MLGDevice* aDevice, MLGBufferType aType,
size_t aDefaultSize);
bool EnsureMappedBuffer(size_t aBytes);
bool GrowBuffer(size_t aBytes);
void ForgetBuffer();
bool Map();
void Unmap();
uint8_t* GetBufferPointer(size_t aBytes, ptrdiff_t* aOutOffset,
RefPtr<MLGBuffer>* aOutBuffer);
protected:
// Note: RefPtr here would cause a cycle. Only MLGDevice should own
// SharedBufferMLGPU objects for now.
MLGDevice* mDevice;
MLGBufferType mType;
size_t mDefaultSize;
bool mCanUseOffsetAllocation;
// When |mBuffer| is non-null, mMaxSize is the buffer size. If mapped, the
// position is between 0 and mMaxSize, otherwise it is always 0.
RefPtr<MLGBuffer> mBuffer;
ptrdiff_t mCurrentPosition;
size_t mMaxSize;
MLGMappedResource mMap;
bool mMapped;
// These are used to track how many frames come in under the default
// buffer size in a row.
size_t mBytesUsedThisFrame;
size_t mNumSmallFrames;
};
class VertexBufferSection final {
friend class SharedVertexBuffer;
public:
VertexBufferSection();
uint32_t Stride() const { return mStride; }
MLGBuffer* GetBuffer() const { return mBuffer; }
ptrdiff_t Offset() const {
MOZ_ASSERT(IsValid());
return mOffset;
}
size_t NumVertices() const { return mNumVertices; }
bool IsValid() const { return !!mBuffer; }
protected:
void Init(MLGBuffer* aBuffer, ptrdiff_t aOffset, size_t aNumVertices,
size_t aStride);
protected:
RefPtr<MLGBuffer> mBuffer;
ptrdiff_t mOffset;
size_t mNumVertices;
size_t mStride;
};
class ConstantBufferSection final {
friend class SharedConstantBuffer;
public:
ConstantBufferSection();
uint32_t NumConstants() const { return NumConstantsForBytes(mNumBytes); }
size_t NumItems() const { return mNumItems; }
uint32_t Offset() const {
MOZ_ASSERT(IsValid());
return mOffset / 16;
}
MLGBuffer* GetBuffer() const { return mBuffer; }
bool IsValid() const { return !!mBuffer; }
bool HasOffset() const { return mOffset != -1; }
protected:
static constexpr size_t NumConstantsForBytes(size_t aBytes) {
return (aBytes + ((256 - (aBytes % 256)) % 256)) / 16;
}
void Init(MLGBuffer* aBuffer, ptrdiff_t aOffset, size_t aBytes,
size_t aNumItems);
protected:
RefPtr<MLGBuffer> mBuffer;
ptrdiff_t mOffset;
size_t mNumBytes;
size_t mNumItems;
};
// Vertex buffers don't need special alignment.
typedef StagingBuffer<0> VertexStagingBuffer;
class SharedVertexBuffer final : public SharedBufferMLGPU {
public:
SharedVertexBuffer(MLGDevice* aDevice, size_t aDefaultSize);
// Allocate a buffer that can be uploaded immediately.
bool Allocate(VertexBufferSection* aHolder,
const VertexStagingBuffer& aStaging) {
return Allocate(aHolder, aStaging.NumItems(), aStaging.SizeOfItem(),
aStaging.GetBufferStart());
}
// Allocate a buffer that can be uploaded immediately. This is the
// direct access version, for cases where a StagingBuffer is not
// needed.
bool Allocate(VertexBufferSection* aHolder, size_t aNumItems,
size_t aSizeOfItem, const void* aData);
template <typename T>
bool Allocate(VertexBufferSection* aHolder, const T& aItem) {
return Allocate(aHolder, 1, sizeof(T), &aItem);
}
};
// To support older Direct3D versions, we need to support one-off MLGBuffers,
// where data is uploaded immediately rather than at the end of all batch
// preparation. We achieve this through a small helper class.
//
// Note: the unmap is not inline sincce we don't include MLGDevice.h.
class MOZ_STACK_CLASS AutoBufferUploadBase {
public:
AutoBufferUploadBase();
~AutoBufferUploadBase();
void Init(void* aPtr) {
MOZ_ASSERT(!mPtr && aPtr);
mPtr = aPtr;
}
void Init(void* aPtr, MLGDevice* aDevice, MLGBuffer* aBuffer);
void* get() { return const_cast<void*>(mPtr); }
private:
void UnmapBuffer();
protected:
RefPtr<MLGDevice> mDevice;
RefPtr<MLGBuffer> mBuffer;
void* mPtr;
};
// This is a typed helper for AutoBufferUploadBase.
template <typename T>
class AutoBufferUpload : public AutoBufferUploadBase {
public:
AutoBufferUpload() = default;
T* operator->() const { return reinterpret_cast<T*>(mPtr); }
};
class SharedConstantBuffer final : public SharedBufferMLGPU {
public:
SharedConstantBuffer(MLGDevice* aDevice, size_t aDefaultSize);
// Allocate a buffer that can be immediately uploaded.
bool Allocate(ConstantBufferSection* aHolder,
const ConstantStagingBuffer& aStaging) {
MOZ_ASSERT(aStaging.NumItems() * aStaging.SizeOfItem() ==
aStaging.NumBytes());
return Allocate(aHolder, aStaging.NumItems(), aStaging.SizeOfItem(),
aStaging.GetBufferStart());
}
// Allocate a buffer of one item that can be immediately uploaded.
template <typename T>
bool Allocate(ConstantBufferSection* aHolder, const T& aItem) {
return Allocate(aHolder, 1, sizeof(aItem), &aItem);
}
// Allocate a buffer of N items that can be immediately uploaded.
template <typename T>
bool Allocate(ConstantBufferSection* aHolder, const T* aItems,
size_t aNumItems) {
return Allocate(aHolder, aNumItems, sizeof(T), aItems);
}
// Allocate a buffer that is uploaded after the caller has finished writing
// to it. This should method should generally not be used unless copying T
// is expensive, since the default immediate-upload version has an implicit
// extra copy to the GPU. This version exposes the mapped memory directly.
template <typename T>
bool Allocate(ConstantBufferSection* aHolder, AutoBufferUpload<T>* aPtr) {
MOZ_ASSERT(sizeof(T) % 16 == 0, "Items must be padded to 16 bytes");
return Allocate(aHolder, aPtr, 1, sizeof(T));
}
private:
bool Allocate(ConstantBufferSection* aHolder, size_t aNumItems,
size_t aSizeOfItem, const void* aData) {
AutoBufferUploadBase ptr;
if (!Allocate(aHolder, &ptr, aNumItems, aSizeOfItem)) {
return false;
}
memcpy(ptr.get(), aData, aNumItems * aSizeOfItem);
return true;
}
bool Allocate(ConstantBufferSection* aHolder, AutoBufferUploadBase* aPtr,
size_t aNumItems, size_t aSizeOfItem);
bool GetBufferPointer(AutoBufferUploadBase* aPtr, size_t aBytes,
ptrdiff_t* aOutOffset, RefPtr<MLGBuffer>* aOutBuffer) {
if (!mCanUseOffsetAllocation) {
uint8_t* ptr = AllocateNewBuffer(aBytes, aOutOffset, aOutBuffer);
if (!ptr) {
return false;
}
aPtr->Init(ptr, mDevice, *aOutBuffer);
return true;
}
// Align up the allocation to 256 bytes, since D3D11 requires that
// constant buffers start at multiples of 16 elements.
size_t alignedBytes = AlignUp<256>::calc(aBytes);
uint8_t* ptr = SharedBufferMLGPU::GetBufferPointer(alignedBytes, aOutOffset,
aOutBuffer);
if (!ptr) {
return false;
}
aPtr->Init(ptr);
return true;
}
uint8_t* AllocateNewBuffer(size_t aBytes, ptrdiff_t* aOutOffset,
RefPtr<MLGBuffer>* aOutBuffer);
private:
size_t mMaxConstantBufferBindSize;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_SharedBufferMLGPU_h

View File

@ -1,18 +0,0 @@
/* -*- 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 "StagingBuffer.h"
#include "MLGDevice.h"
#include "ShaderDefinitionsMLGPU.h"
namespace mozilla {
namespace layers {
ConstantStagingBuffer::ConstantStagingBuffer(MLGDevice* aDevice)
: StagingBuffer(mlg::kMaxConstantBufferSize) {}
} // namespace layers
} // namespace mozilla

View File

@ -1,271 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_StagingBuffer_h
#define mozilla_gfx_layers_mlgpu_StagingBuffer_h
#include "mozilla/MathAlgorithms.h"
#include "mozilla/UniquePtr.h"
#include "UtilityMLGPU.h"
#include <algorithm>
#include <utility>
#include <limits.h>
namespace mozilla {
namespace layers {
class MLGDevice;
// A StagingBuffer is a writable memory buffer for arbitrary contents.
template <size_t Alignment = 0>
class StagingBuffer {
public:
StagingBuffer() : StagingBuffer(0) {}
// By default, staging buffers operate in "forward" mode: items are added to
// the end of the buffer. In "reverse" mode the cursor is at the end of the
// buffer, and items are added to the beginning.
//
// This must be called before the buffer is written.
void SetReversed() {
MOZ_ASSERT(IsEmpty());
mReversed = true;
}
// Write a series of components as a single item. When this is first used, the
// buffer records the initial item size and requires that all future items be
// the exact same size.
//
// This directs to either AppendItem or PrependItem depending on the buffer
// state.
template <typename T>
bool AddItem(const T& aItem) {
if (mReversed) {
return PrependItem(aItem);
}
return AppendItem(aItem);
}
// Helper for adding a single item as two components.
template <typename T1, typename T2>
bool AddItem(const T1& aItem1, const T2& aItem2) {
if (mReversed) {
return PrependItem(aItem1, aItem2);
}
return AppendItem(aItem1, aItem2);
}
// This may only be called on forward buffers.
template <typename T>
bool AppendItem(const T& aItem) {
MOZ_ASSERT(!mReversed);
size_t alignedBytes = AlignUp<Alignment>::calc(sizeof(aItem));
if (!mUniformSize) {
mUniformSize = alignedBytes;
}
if (!EnsureForwardRoomFor(alignedBytes)) {
return false;
}
if (mUniformSize != alignedBytes) {
MOZ_ASSERT_UNREACHABLE("item of incorrect size added!");
return false;
}
*reinterpret_cast<T*>(mPos) = aItem;
mPos += alignedBytes;
MOZ_ASSERT(mPos <= mEnd);
mNumItems++;
return true;
}
// Append an item in two stages.
template <typename T1, typename T2>
bool AppendItem(const T1& aFirst, const T2& aSecond) {
struct Combined {
T1 first;
T2 second;
} value = {aFirst, aSecond};
// The combined value must be packed.
static_assert(sizeof(value) == sizeof(aFirst) + sizeof(aSecond),
"Items must be packed within struct");
return AppendItem(value);
}
// This may only be called on reversed buffers.
template <typename T>
bool PrependItem(const T& aItem) {
MOZ_ASSERT(mReversed);
size_t alignedBytes = AlignUp<Alignment>::calc(sizeof(aItem));
if (!mUniformSize) {
mUniformSize = alignedBytes;
}
if (!EnsureBackwardRoomFor(alignedBytes)) {
return false;
}
if (mUniformSize != alignedBytes) {
MOZ_ASSERT_UNREACHABLE("item of incorrect size added!");
return false;
}
mPos -= alignedBytes;
*reinterpret_cast<T*>(mPos) = aItem;
MOZ_ASSERT(mPos >= mBuffer.get());
mNumItems++;
return true;
}
// Prepend an item in two stages.
template <typename T1, typename T2>
bool PrependItem(const T1& aFirst, const T2& aSecond) {
struct Combined {
T1 first;
T2 second;
} value = {aFirst, aSecond};
// The combined value must be packed.
static_assert(sizeof(value) == sizeof(aFirst) + sizeof(aSecond),
"Items must be packed within struct");
return PrependItem(value);
}
size_t NumBytes() const {
return mReversed ? mEnd - mPos : mPos - mBuffer.get();
}
uint8_t* GetBufferStart() const { return mReversed ? mPos : mBuffer.get(); }
size_t SizeOfItem() const { return mUniformSize; }
size_t NumItems() const { return mNumItems; }
void Reset() {
mPos = mReversed ? mEnd : mBuffer.get();
mUniformSize = 0;
mNumItems = 0;
}
// RestorePosition must only be called with a previous call to
// GetPosition.
typedef std::pair<size_t, size_t> Position;
Position GetPosition() const { return std::make_pair(NumBytes(), mNumItems); }
void RestorePosition(const Position& aPosition) {
mPos = mBuffer.get() + aPosition.first;
mNumItems = aPosition.second;
if (mNumItems == 0) {
mUniformSize = 0;
}
// Make sure the buffer is still coherent.
MOZ_ASSERT(mPos >= mBuffer.get() && mPos <= mEnd);
MOZ_ASSERT(mNumItems * mUniformSize == NumBytes());
}
bool IsEmpty() const { return mNumItems == 0; }
protected:
explicit StagingBuffer(size_t aMaxSize)
: mPos(nullptr),
mEnd(nullptr),
mUniformSize(0),
mNumItems(0),
mMaxSize(aMaxSize),
mReversed(false) {}
static const size_t kDefaultSize = 8;
bool EnsureForwardRoomFor(size_t aAlignedBytes) {
if (size_t(mEnd - mPos) < aAlignedBytes) {
return GrowBuffer(aAlignedBytes);
}
return true;
}
bool EnsureBackwardRoomFor(size_t aAlignedBytes) {
if (size_t(mPos - mBuffer.get()) < aAlignedBytes) {
return GrowBuffer(aAlignedBytes);
}
return true;
}
bool GrowBuffer(size_t aAlignedBytes) {
// We should not be writing items that are potentially bigger than the
// maximum constant buffer size, that's crazy. An assert should be good
// enough since the size of writes is static - and shader compilers
// would explode anyway.
MOZ_ASSERT_IF(mMaxSize, aAlignedBytes < mMaxSize);
MOZ_ASSERT_IF(mMaxSize, kDefaultSize * Alignment < mMaxSize);
if (!mBuffer) {
size_t newSize = std::max(kDefaultSize * Alignment, aAlignedBytes);
MOZ_ASSERT_IF(mMaxSize, newSize < mMaxSize);
mBuffer = MakeUnique<uint8_t[]>(newSize);
mEnd = mBuffer.get() + newSize;
mPos = mReversed ? mEnd : mBuffer.get();
return true;
}
// Take the bigger of exact-fit or 1.5x the previous size, and make sure
// the new size doesn't overflow size_t. If needed, clamp to the max
// size.
size_t oldSize = mEnd - mBuffer.get();
size_t trySize = std::max(oldSize + aAlignedBytes, oldSize + oldSize / 2);
size_t newSize = mMaxSize ? std::min(trySize, mMaxSize) : trySize;
if (newSize < oldSize || newSize - oldSize < aAlignedBytes) {
return false;
}
UniquePtr<uint8_t[]> newBuffer = MakeUnique<uint8_t[]>(newSize);
if (!newBuffer) {
return false;
}
// When the buffer is in reverse mode, we have to copy from the end of the
// buffer, not the beginning.
if (mReversed) {
size_t usedBytes = mEnd - mPos;
size_t newPos = newSize - usedBytes;
MOZ_RELEASE_ASSERT(newPos + usedBytes <= newSize);
memcpy(newBuffer.get() + newPos, mPos, usedBytes);
mPos = newBuffer.get() + newPos;
} else {
size_t usedBytes = mPos - mBuffer.get();
MOZ_RELEASE_ASSERT(usedBytes <= newSize);
memcpy(newBuffer.get(), mBuffer.get(), usedBytes);
mPos = newBuffer.get() + usedBytes;
}
mEnd = newBuffer.get() + newSize;
mBuffer = std::move(newBuffer);
MOZ_RELEASE_ASSERT(mPos >= mBuffer.get() && mPos <= mEnd);
return true;
}
protected:
UniquePtr<uint8_t[]> mBuffer;
uint8_t* mPos;
uint8_t* mEnd;
size_t mUniformSize;
size_t mNumItems;
size_t mMaxSize;
bool mReversed;
};
class ConstantStagingBuffer : public StagingBuffer<16> {
public:
explicit ConstantStagingBuffer(MLGDevice* aDevice);
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_StagingBuffer_h

View File

@ -1,96 +0,0 @@
/* -*- 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 "TextureSourceProviderMLGPU.h"
#include "LayerManagerMLGPU.h"
#include "MLGDevice.h"
#ifdef XP_WIN
# include "mozilla/layers/MLGDeviceD3D11.h"
#endif
namespace mozilla {
namespace layers {
TextureSourceProviderMLGPU::TextureSourceProviderMLGPU(
LayerManagerMLGPU* aLayerManager, MLGDevice* aDevice)
: mLayerManager(aLayerManager), mDevice(aDevice) {}
TextureSourceProviderMLGPU::~TextureSourceProviderMLGPU() = default;
int32_t TextureSourceProviderMLGPU::GetMaxTextureSize() const {
if (!mDevice) {
return 0;
}
return mDevice->GetMaxTextureSize();
}
bool TextureSourceProviderMLGPU::SupportsEffect(EffectTypes aEffect) {
switch (aEffect) {
case EffectTypes::YCBCR:
return true;
default:
MOZ_ASSERT_UNREACHABLE("NYI");
}
return false;
}
bool TextureSourceProviderMLGPU::IsValid() const { return !!mLayerManager; }
void TextureSourceProviderMLGPU::Destroy() {
mLayerManager = nullptr;
mDevice = nullptr;
TextureSourceProvider::Destroy();
}
#ifdef XP_WIN
ID3D11Device* TextureSourceProviderMLGPU::GetD3D11Device() const {
if (!mDevice) {
return nullptr;
}
return mDevice->AsD3D11()->GetD3D11Device();
}
#endif
TimeStamp TextureSourceProviderMLGPU::GetLastCompositionEndTime() const {
if (!mLayerManager) {
return TimeStamp();
}
return mLayerManager->GetLastCompositionEndTime();
}
already_AddRefed<DataTextureSource>
TextureSourceProviderMLGPU::CreateDataTextureSource(TextureFlags aFlags) {
RefPtr<DataTextureSource> texture = mDevice->CreateDataTextureSource(aFlags);
return texture.forget();
}
already_AddRefed<DataTextureSource>
TextureSourceProviderMLGPU::CreateDataTextureSourceAround(
gfx::DataSourceSurface* aSurface) {
MOZ_ASSERT_UNREACHABLE("NYI");
return nullptr;
}
void TextureSourceProviderMLGPU::UnlockAfterComposition(TextureHost* aTexture) {
TextureSourceProvider::UnlockAfterComposition(aTexture);
// If this is being called after we shutdown the compositor, we must finish
// read unlocking now to prevent a cycle.
if (!IsValid()) {
ReadUnlockTextures();
}
}
bool TextureSourceProviderMLGPU::NotifyNotUsedAfterComposition(
TextureHost* aTextureHost) {
if (!IsValid()) {
return false;
}
return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost);
}
} // namespace layers
} // namespace mozilla

View File

@ -1,56 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_TextureSourceProviderMLGPU_h
#define mozilla_gfx_layers_mlgpu_TextureSourceProviderMLGPU_h
#include "mozilla/layers/TextureSourceProvider.h"
namespace mozilla {
namespace layers {
class MLGDevice;
class LayerManagerMLGPU;
class TextureSourceProviderMLGPU final : public TextureSourceProvider {
public:
TextureSourceProviderMLGPU(LayerManagerMLGPU* aLayerManager,
MLGDevice* aDevice);
virtual ~TextureSourceProviderMLGPU();
already_AddRefed<DataTextureSource> CreateDataTextureSource(
TextureFlags aFlags) override;
already_AddRefed<DataTextureSource> CreateDataTextureSourceAround(
gfx::DataSourceSurface* aSurface) override;
void UnlockAfterComposition(TextureHost* aTexture) override;
bool NotifyNotUsedAfterComposition(TextureHost* aTextureHost) override;
int32_t GetMaxTextureSize() const override;
TimeStamp GetLastCompositionEndTime() const override;
bool SupportsEffect(EffectTypes aEffect) override;
bool IsValid() const override;
#ifdef XP_WIN
ID3D11Device* GetD3D11Device() const override;
#endif
void ReadUnlockTextures() { TextureSourceProvider::ReadUnlockTextures(); }
// Release references to the layer manager.
void Destroy() override;
private:
// Using RefPtr<> here would be a circular reference.
LayerManagerMLGPU* mLayerManager;
RefPtr<MLGDevice> mDevice;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_TextureSourceProviderMLGPU_h

View File

@ -1,196 +0,0 @@
/* -*- 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 "TexturedLayerMLGPU.h"
#include "LayerManagerMLGPU.h"
#include "RenderViewMLGPU.h"
#include "FrameBuilder.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/ImageHost.h"
#include "UnitTransforms.h"
namespace mozilla {
namespace layers {
using namespace gfx;
TexturedLayerMLGPU::TexturedLayerMLGPU(LayerManagerMLGPU* aManager)
: LayerMLGPU(aManager) {}
TexturedLayerMLGPU::~TexturedLayerMLGPU() {
// Note: we have to cleanup resources in derived classes, since we can't
// easily tell in our destructor if we have a TempImageLayerMLGPU, which
// should not have its compositable detached, and we can't call GetLayer
// here.
}
bool TexturedLayerMLGPU::SetCompositableHost(CompositableHost* aHost) {
switch (aHost->GetType()) {
case CompositableType::IMAGE:
mHost = aHost->AsImageHost();
return true;
default:
return false;
}
}
CompositableHost* TexturedLayerMLGPU::GetCompositableHost() {
if (mHost && mHost->IsAttached()) {
return mHost.get();
}
return nullptr;
}
RefPtr<TextureSource> TexturedLayerMLGPU::BindAndGetTexture() {
if (!mHost) {
return nullptr;
}
LayerManagerMLGPU* lm = GetLayerManager()->AsLayerManagerMLGPU();
// Note: we don't call FinishRendering since mask layers do not need
// composite notifications or bias updates. (This function should
// not be called for non-mask-layers).
ImageHost::RenderInfo info;
if (!mHost->PrepareToRender(lm->GetTextureSourceProvider(), &info)) {
return nullptr;
}
RefPtr<TextureSource> source = mHost->AcquireTextureSource(info);
if (!source) {
return nullptr;
}
mTexture = source;
return source;
}
bool TexturedLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder) {
if (!mHost) {
return false;
}
LayerManagerMLGPU* lm = GetLayerManager()->AsLayerManagerMLGPU();
ImageHost::RenderInfo info;
if (!mHost->PrepareToRender(lm->GetTextureSourceProvider(), &info)) {
return false;
}
RefPtr<TextureSource> source = mHost->AcquireTextureSource(info);
if (!source) {
return false;
}
if (source->AsBigImageIterator()) {
mBigImageTexture = source;
mTexture = nullptr;
} else {
mTexture = source;
}
mPictureRect = IntRect(0, 0, info.img->mPictureRect.Width(),
info.img->mPictureRect.Height());
mHost->FinishRendering(info);
return true;
}
void TexturedLayerMLGPU::AssignToView(FrameBuilder* aBuilder,
RenderViewMLGPU* aView,
Maybe<Polygon>&& aGeometry) {
if (mBigImageTexture) {
BigImageIterator* iter = mBigImageTexture->AsBigImageIterator();
iter->BeginBigImageIteration();
AssignBigImage(aBuilder, aView, iter, aGeometry);
iter->EndBigImageIteration();
} else {
LayerMLGPU::AssignToView(aBuilder, aView, std::move(aGeometry));
}
}
void TexturedLayerMLGPU::AssignBigImage(FrameBuilder* aBuilder,
RenderViewMLGPU* aView,
BigImageIterator* aIter,
const Maybe<Polygon>& aGeometry) {
const Matrix4x4& transform = GetLayer()->GetEffectiveTransformForBuffer();
// Note that we don't need to assign these in any particular order, since
// they do not overlap.
do {
IntRect tileRect = aIter->GetTileRect();
IntRect rect = tileRect.Intersect(mPictureRect);
if (rect.IsEmpty()) {
continue;
}
{
Rect screenRect = transform.TransformBounds(Rect(rect));
screenRect.MoveBy(-aView->GetTargetOffset());
screenRect =
screenRect.Intersect(Rect(mComputedClipRect.ToUnknownRect()));
if (screenRect.IsEmpty()) {
// This tile is not in the clip region, so skip it.
continue;
}
}
RefPtr<TextureSource> tile = mBigImageTexture->ExtractCurrentTile();
if (!tile) {
continue;
}
// Create a temporary item.
RefPtr<TempImageLayerMLGPU> item =
new TempImageLayerMLGPU(aBuilder->GetManager());
item->Init(this, tile, rect);
Maybe<Polygon> geometry = aGeometry;
item->AddBoundsToView(aBuilder, aView, std::move(geometry));
// Since the layer tree is not holding this alive, we have to ask the
// FrameBuilder to do it for us.
aBuilder->RetainTemporaryLayer(item);
} while (aIter->NextTile());
}
TempImageLayerMLGPU::TempImageLayerMLGPU(LayerManagerMLGPU* aManager)
: ImageLayer(aManager, static_cast<HostLayer*>(this)),
TexturedLayerMLGPU(aManager),
mFilter(gfx::SamplingFilter::GOOD),
mIsOpaque(false) {}
TempImageLayerMLGPU::~TempImageLayerMLGPU() = default;
void TempImageLayerMLGPU::Init(TexturedLayerMLGPU* aSource,
const RefPtr<TextureSource>& aTexture,
const gfx::IntRect& aPictureRect) {
// ImageLayer properties.
mEffectiveTransform = aSource->GetLayer()->GetEffectiveTransform();
mEffectiveTransformForBuffer =
aSource->GetLayer()->GetEffectiveTransformForBuffer();
// Base LayerMLGPU properties.
mComputedClipRect = aSource->GetComputedClipRect();
mMask = aSource->GetMask();
mComputedOpacity = aSource->GetComputedOpacity();
// TexturedLayerMLGPU properties.
mHost = aSource->GetImageHost();
mTexture = aTexture;
mPictureRect = aPictureRect;
// Local properties.
mFilter = aSource->GetSamplingFilter();
mShadowVisibleRegion = aSource->GetShadowVisibleRegion();
mIsOpaque = aSource->IsContentOpaque();
// Set this layer to prepared so IsPrepared() assertions don't fire.
MarkPrepared();
}
} // namespace layers
} // namespace mozilla

View File

@ -1,90 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_TexturedLayerMLGPU_h
#define mozilla_gfx_layers_mlgpu_TexturedLayerMLGPU_h
#include "LayerMLGPU.h"
#include "ImageLayers.h"
#include "mozilla/layers/ImageHost.h"
namespace mozilla {
namespace layers {
// This is the base class for canvas and image layers.
class TexturedLayerMLGPU : public LayerMLGPU {
public:
TexturedLayerMLGPU* AsTexturedLayerMLGPU() override { return this; }
virtual gfx::SamplingFilter GetSamplingFilter() = 0;
bool SetCompositableHost(CompositableHost* aHost) override;
CompositableHost* GetCompositableHost() override;
void AssignToView(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
Maybe<gfx::Polygon>&& aGeometry) override;
TextureSource* GetTexture() const { return mTexture; }
ImageHost* GetImageHost() const { return mHost; }
// Return the scale factor from the texture source to the picture rect.
virtual Maybe<gfx::Size> GetPictureScale() const { return Nothing(); }
// Mask layers aren't prepared like normal layers. They are bound as
// mask operations are built. Mask layers are never tiled (they are
// scaled to a lower resolution if too big), so this pathway returns
// a TextureSource.
RefPtr<TextureSource> BindAndGetTexture();
protected:
explicit TexturedLayerMLGPU(LayerManagerMLGPU* aManager);
virtual ~TexturedLayerMLGPU();
void AssignBigImage(FrameBuilder* aBuilder, RenderViewMLGPU* aView,
BigImageIterator* aIter,
const Maybe<gfx::Polygon>& aGeometry);
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
protected:
RefPtr<ImageHost> mHost;
RefPtr<TextureSource> mTexture;
RefPtr<TextureSource> mBigImageTexture;
gfx::IntRect mPictureRect;
};
// This is a pseudo layer that wraps a tile in an ImageLayer backed by a
// BigImage. Without this, we wouldn't have anything sensible to add to
// RenderPasses. In the future we could potentially consume the source
// layer more intelligently instead (for example, having it compute
// which textures are relevant for a given tile).
class TempImageLayerMLGPU final : public ImageLayer, public TexturedLayerMLGPU {
public:
explicit TempImageLayerMLGPU(LayerManagerMLGPU* aManager);
// Layer
HostLayer* AsHostLayer() override { return this; }
gfx::SamplingFilter GetSamplingFilter() override { return mFilter; }
bool IsContentOpaque() override { return mIsOpaque; }
void Init(TexturedLayerMLGPU* aSource, const RefPtr<TextureSource>& aTexture,
const gfx::IntRect& aPictureRect);
// HostLayer
Layer* GetLayer() override { return this; }
protected:
virtual ~TempImageLayerMLGPU();
private:
gfx::SamplingFilter mFilter;
bool mIsOpaque;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_mlgpu_TexturedLayerMLGPU_h

View File

@ -1,45 +0,0 @@
/* -*- 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_gfx_layers_mlgpu_UtilityMLGPU_h
#define mozilla_gfx_layers_mlgpu_UtilityMLGPU_h
#include "mozilla/Assertions.h"
#include "mozilla/MathAlgorithms.h"
namespace mozilla {
namespace layers {
template <size_t T>
struct AlignUp {
static inline size_t calc(size_t aAmount) {
MOZ_ASSERT(IsPowerOfTwo(T), "alignment must be a power of two");
return aAmount + ((T - (aAmount % T)) % T);
}
};
template <>
struct AlignUp<0> {
static inline size_t calc(size_t aAmount) { return aAmount; }
};
} // namespace layers
} // namespace mozilla
#ifdef ENABLE_AL_LOGGING
# define AL_LOG(...) printf_stderr("AL: " __VA_ARGS__)
# define AL_LOG_IF(cond, ...) \
do { \
if (cond) { \
printf_stderr("AL: " __VA_ARGS__); \
} \
} while (0)
#else
# define AL_LOG(...)
# define AL_LOG_IF(...)
#endif
#endif // mozilla_gfx_layers_mlgpu_UtilityMLGPU_h

View File

@ -64,14 +64,12 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
"d3d11/DeviceAttachmentsD3D11.h",
"d3d11/DiagnosticsD3D11.h",
"d3d11/HelpersD3D11.h",
"d3d11/MLGDeviceD3D11.h",
"d3d11/ReadbackManagerD3D11.h",
"d3d11/ShaderDefinitionsD3D11.h",
"d3d11/TextureD3D11.h",
]
UNIFIED_SOURCES += [
"d3d11/DiagnosticsD3D11.cpp",
"d3d11/MLGDeviceD3D11.cpp",
"d3d11/TextureD3D11.cpp",
]
SOURCES += [
@ -228,14 +226,6 @@ EXPORTS.mozilla.layers += [
"LayersHelpers.h",
"LayersTypes.h",
"MemoryPressureObserver.h",
"mlgpu/LayerManagerMLGPU.h",
"mlgpu/LayerMLGPU.h",
"mlgpu/MemoryReportingMLGPU.h",
"mlgpu/MLGDevice.h",
"mlgpu/MLGDeviceTypes.h",
"mlgpu/MLGPUScreenshotGrabber.h",
"mlgpu/ShaderDefinitionsMLGPU.h",
"mlgpu/UtilityMLGPU.h",
"NativeLayer.h",
"OOPCanvasRenderer.h",
"opengl/CompositingRenderTargetOGL.h",
@ -504,24 +494,6 @@ UNIFIED_SOURCES += [
"LayersTypes.cpp",
"LayerTreeInvalidation.cpp",
"MemoryPressureObserver.cpp",
"mlgpu/BufferCache.cpp",
"mlgpu/CanvasLayerMLGPU.cpp",
"mlgpu/ContainerLayerMLGPU.cpp",
"mlgpu/FrameBuilder.cpp",
"mlgpu/ImageLayerMLGPU.cpp",
"mlgpu/LayerManagerMLGPU.cpp",
"mlgpu/LayerMLGPU.cpp",
"mlgpu/MaskOperation.cpp",
"mlgpu/MemoryReportingMLGPU.cpp",
"mlgpu/MLGDevice.cpp",
"mlgpu/MLGPUScreenshotGrabber.cpp",
"mlgpu/PaintedLayerMLGPU.cpp",
"mlgpu/RenderPassMLGPU.cpp",
"mlgpu/RenderViewMLGPU.cpp",
"mlgpu/SharedBufferMLGPU.cpp",
"mlgpu/StagingBuffer.cpp",
"mlgpu/TexturedLayerMLGPU.cpp",
"mlgpu/TextureSourceProviderMLGPU.cpp",
"opengl/CompositingRenderTargetOGL.cpp",
"opengl/CompositorOGL.cpp",
"opengl/GLBlitTextureImageHelper.cpp",
@ -615,11 +587,6 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
script="d3d11/genshaders.py",
inputs=["d3d11/shaders.manifest"],
)
GeneratedFile(
"MLGShaders.h",
script="d3d11/genshaders.py",
inputs=["d3d11/mlgshaders/shaders.manifest"],
)
LOCAL_INCLUDES += [
"/docshell/base", # for nsDocShell.h

View File

@ -21,7 +21,6 @@
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/DeviceAttachmentsD3D11.h"
#include "mozilla/layers/MLGDeviceD3D11.h"
#include "mozilla/layers/PaintThread.h"
#include "mozilla/Preferences.h"
#include "nsExceptionHandler.h"
@ -293,11 +292,6 @@ bool DeviceManagerDx::CreateCompositorDevices() {
MOZ_ASSERT(!mCompositorDevice);
ReleaseD3D11();
// Sync Advanced-Layers with D3D11.
if (gfxConfig::IsEnabled(Feature::ADVANCED_LAYERS)) {
gfxConfig::SetFailed(Feature::ADVANCED_LAYERS, FeatureStatus::Unavailable,
"Requires D3D11", "FEATURE_FAILURE_NO_D3D11"_ns);
}
return false;
}
@ -935,84 +929,6 @@ RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice() {
return device;
}
RefPtr<MLGDevice> DeviceManagerDx::GetMLGDevice() {
MutexAutoLock lock(mDeviceLock);
if (!mMLGDevice) {
MutexAutoUnlock unlock(mDeviceLock);
CreateMLGDevice();
}
return mMLGDevice;
}
static void DisableAdvancedLayers(FeatureStatus aStatus,
const nsCString aMessage,
const nsCString& aFailureId) {
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(NS_NewRunnableFunction(
"DisableAdvancedLayers", [aStatus, aMessage, aFailureId]() -> void {
DisableAdvancedLayers(aStatus, aMessage, aFailureId);
}));
return;
}
MOZ_ASSERT(NS_IsMainThread());
FeatureState& al = gfxConfig::GetFeature(Feature::ADVANCED_LAYERS);
if (!al.IsEnabled()) {
return;
}
al.SetFailed(aStatus, aMessage.get(), aFailureId);
FeatureFailure info(aStatus, aMessage, aFailureId);
if (GPUParent* gpu = GPUParent::GetSingleton()) {
Unused << gpu->SendUpdateFeature(Feature::ADVANCED_LAYERS, info);
}
if (aFailureId.Length()) {
nsString failureId = NS_ConvertUTF8toUTF16(aFailureId.get());
Telemetry::ScalarAdd(Telemetry::ScalarID::GFX_ADVANCED_LAYERS_FAILURE_ID,
failureId, 1);
}
// Notify TelemetryEnvironment.jsm.
if (RefPtr<nsIObserverService> obs =
mozilla::services::GetObserverService()) {
obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
}
}
void DeviceManagerDx::CreateMLGDevice() {
MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
RefPtr<ID3D11Device> d3d11Device = GetCompositorDevice();
if (!d3d11Device) {
DisableAdvancedLayers(FeatureStatus::Unavailable,
"Advanced-layers requires a D3D11 device"_ns,
"FEATURE_FAILURE_NEED_D3D11_DEVICE"_ns);
return;
}
RefPtr<MLGDeviceD3D11> device = new MLGDeviceD3D11(d3d11Device);
if (!device->Initialize()) {
DisableAdvancedLayers(FeatureStatus::Failed, device->GetFailureMessage(),
device->GetFailureId());
return;
}
// While the lock was unheld, we should not have created an MLGDevice, since
// this should only be called on the compositor thread.
MutexAutoLock lock(mDeviceLock);
MOZ_ASSERT(!mMLGDevice);
// Only set the MLGDevice if the compositor device is still the same.
// Otherwise we could possibly have a bad MLGDevice if a device reset
// just occurred.
if (mCompositorDevice == d3d11Device) {
mMLGDevice = device;
}
}
void DeviceManagerDx::ResetDevices() {
// Flush the paint thread before revoking all these singletons. This
// should ensure that the paint thread doesn't start mixing and matching
@ -1028,7 +944,6 @@ void DeviceManagerDx::ResetDevices() {
mAdapter = nullptr;
mCompositorAttachments = nullptr;
mMLGDevice = nullptr;
mCompositorDevice = nullptr;
mContentDevice = nullptr;
mCanvasDevice = nullptr;
@ -1425,20 +1340,12 @@ void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() {
return;
}
bool enableAL = gfxConfig::IsEnabled(Feature::ADVANCED_LAYERS) &&
!gfx::gfxVars::UseSoftwareWebRender();
RefPtr<Runnable> task = NS_NewRunnableFunction(
"DeviceManagerDx::PreloadAttachmentsOnCompositorThread",
[enableAL]() -> void {
"DeviceManagerDx::PreloadAttachmentsOnCompositorThread", []() -> void {
if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
if (enableAL) {
dm->GetMLGDevice();
} else {
RefPtr<ID3D11Device> device;
RefPtr<layers::DeviceAttachmentsD3D11> attachments;
dm->GetCompositorDevices(&device, &attachments);
}
RefPtr<ID3D11Device> device;
RefPtr<layers::DeviceAttachmentsD3D11> attachments;
dm->GetCompositorDevices(&device, &attachments);
}
});
CompositorThread()->Dispatch(task.forget());

View File

@ -41,7 +41,6 @@ namespace mozilla {
class ScopedGfxFeatureReporter;
namespace layers {
class DeviceAttachmentsD3D11;
class MLGDevice;
} // namespace layers
namespace gfx {
@ -63,7 +62,6 @@ class DeviceManagerDx final {
RefPtr<IDCompositionDevice2> GetDirectCompositionDevice();
RefPtr<ID3D11Device> GetVRDevice();
RefPtr<ID3D11Device> CreateDecoderDevice();
RefPtr<layers::MLGDevice> GetMLGDevice();
IDirectDraw7* GetDirectDraw();
unsigned GetCompositorFeatureLevel() const;
@ -144,7 +142,6 @@ class DeviceManagerDx final {
RefPtr<ID3D11Device>& aOutDevice);
void CreateWARPCompositorDevice();
void CreateMLGDevice();
bool CreateVRDevice();
mozilla::gfx::FeatureStatus CreateContentDevice();
@ -184,7 +181,6 @@ class DeviceManagerDx final {
RefPtr<ID3D11Device> mDecoderDevice;
RefPtr<IDCompositionDevice2> mDirectCompositionDevice;
RefPtr<layers::DeviceAttachmentsD3D11> mCompositorAttachments;
RefPtr<layers::MLGDevice> mMLGDevice;
bool mCompositorDeviceSupportsVideo;
Maybe<D3D11DeviceStatus> mDeviceStatus;

View File

@ -150,7 +150,6 @@ static const uint32_t kDefaultGlyphCacheSize = -1;
#include "VRManager.h"
#include "VRManagerChild.h"
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/layers/MemoryReportingMLGPU.h"
#include "prsystem.h"
using namespace mozilla;
@ -1066,7 +1065,6 @@ void gfxPlatform::Init() {
#ifdef USE_SKIA
RegisterStrongMemoryReporter(new SkMemoryReporter());
#endif
mlg::InitializeMemoryReporters();
#ifdef USE_SKIA
uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
@ -3506,7 +3504,6 @@ void gfxPlatform::ImportGPUDeviceData(
MOZ_ASSERT(XRE_IsParentProcess());
gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
gfxConfig::ImportChange(Feature::ADVANCED_LAYERS, aData.advancedLayers());
}
bool gfxPlatform::SupportsApzTouchInput() const {

View File

@ -381,20 +381,6 @@ void gfxWindowsPlatform::InitAcceleration() {
void gfxWindowsPlatform::InitWebRenderConfig() {
gfxPlatform::InitWebRenderConfig();
if (XRE_IsParentProcess()) {
bool prev =
Preferences::GetBool("sanity-test.webrender.force-disabled", false);
bool current = Preferences::GetBool("gfx.webrender.force-disabled", false);
// When "gfx.webrender.force-disabled" pref is changed from false to true,
// set "layers.mlgpu.sanity-test-failed" pref to false.
// "layers.mlgpu.sanity-test-failed" pref is re-tested by SanityTest.jsm.
bool doRetest = !prev && current;
if (doRetest) {
Preferences::SetBool("layers.mlgpu.sanity-test-failed", false);
}
// Need to be called after gfxPlatform::InitWebRenderConfig().
InitializeAdvancedLayersConfig();
}
if (gfxVars::UseWebRender()) {
UpdateBackendPrefs();
@ -444,13 +430,11 @@ bool gfxWindowsPlatform::HandleDeviceReset() {
gfxAlphaBoxBlur::ShutdownBlurCache();
gfxConfig::Reset(Feature::D3D11_COMPOSITING);
gfxConfig::Reset(Feature::ADVANCED_LAYERS);
gfxConfig::Reset(Feature::D3D11_HW_ANGLE);
gfxConfig::Reset(Feature::DIRECT2D);
InitializeConfig();
// XXX Add InitWebRenderConfig() calling.
InitializeAdvancedLayersConfig();
if (mInitializedDevices) {
InitGPUProcessSupport();
InitializeDevices();
@ -1361,44 +1345,6 @@ void gfxWindowsPlatform::InitializeD3D11Config() {
}
}
/* static */
void gfxWindowsPlatform::InitializeAdvancedLayersConfig() {
// Only enable Advanced Layers if D3D11 succeeded.
if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
return;
}
FeatureState& al = gfxConfig::GetFeature(Feature::ADVANCED_LAYERS);
al.SetDefaultFromPref(StaticPrefs::GetPrefName_layers_mlgpu_enabled(),
true /* aIsEnablePref */,
StaticPrefs::GetPrefDefault_layers_mlgpu_enabled());
// Windows 7 has an extra pref since it uses totally different buffer paths
// that haven't been performance tested yet.
if (al.IsEnabled() && !IsWin8OrLater()) {
if (StaticPrefs::layers_mlgpu_enable_on_windows7_AtStartup()) {
al.UserEnable("Enabled for Windows 7 via user-preference");
} else {
al.Disable(FeatureStatus::Disabled,
"Advanced Layers is disabled on Windows 7 by default",
"FEATURE_FAILURE_DISABLED_ON_WIN7"_ns);
}
}
nsCString message, failureId;
if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_ADVANCED_LAYERS, &message,
failureId)) {
al.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
} else if (gfxVars::UseWebRender()) {
al.Disable(FeatureStatus::Blocked,
"Blocked from fallback candidate by WebRender usage",
"FEATURE_BLOCKED_BY_WEBRENDER_USAGE"_ns);
} else if (Preferences::GetBool("layers.mlgpu.sanity-test-failed", false)) {
al.Disable(FeatureStatus::Broken, "Failed to render sanity test",
"FEATURE_FAILURE_FAILED_TO_RENDER"_ns);
}
}
/* static */
void gfxWindowsPlatform::RecordContentDeviceFailure(
TelemetryDeviceCode aDevice) {

View File

@ -256,7 +256,6 @@ class gfxWindowsPlatform final : public gfxPlatform {
void InitializeD3D11Config();
void InitializeD2DConfig();
void InitializeDirectDrawConfig();
void InitializeAdvancedLayersConfig();
void RecordStartupTelemetry();

View File

@ -105,7 +105,6 @@ void VRChild::Init() {
gfxConfig::GetValue(Feature::D3D11_COMPOSITING);
devicePrefs.oglCompositing() =
gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
devicePrefs.advancedLayers() = gfxConfig::GetValue(Feature::ADVANCED_LAYERS);
devicePrefs.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
SendInit(updates, devicePrefs);

View File

@ -55,7 +55,6 @@ IPCResult VRParent::RecvInit(nsTArray<GfxVarUpdate>&& vars,
gfxConfig::Inherit(Feature::D3D11_COMPOSITING,
devicePrefs.d3d11Compositing());
gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, devicePrefs.oglCompositing());
gfxConfig::Inherit(Feature::ADVANCED_LAYERS, devicePrefs.advancedLayers());
gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1());
#if defined(XP_WIN)

View File

@ -3020,16 +3020,6 @@ void nsDisplayItem::FuseClipChainUpTo(nsDisplayListBuilder* aBuilder,
}
}
bool nsDisplayItem::ShouldUseAdvancedLayer(LayerManager* aManager,
PrefFunc aFunc) const {
return CanUseAdvancedLayer(aManager) ? aFunc() : false;
}
bool nsDisplayItem::CanUseAdvancedLayer(LayerManager* aManager) const {
return StaticPrefs::layers_advanced_basic_layer_enabled() || !aManager ||
aManager->GetBackendType() == layers::LayersBackend::LAYERS_WR;
}
static const DisplayItemClipChain* FindCommonAncestorClipForIntersection(
const DisplayItemClipChain* aOne, const DisplayItemClipChain* aTwo) {
for (const ActiveScrolledRoot* asr =

View File

@ -3111,8 +3111,6 @@ class nsDisplayItem : public nsDisplayItemBase {
protected:
typedef bool (*PrefFunc)(void);
bool ShouldUseAdvancedLayer(LayerManager* aManager, PrefFunc aFunc) const;
bool CanUseAdvancedLayer(LayerManager* aManager) const;
void SetHasHitTestInfo() { mItemFlags += ItemFlag::HasHitTestInfo; }
RefPtr<const DisplayItemClipChain> mClipChain;

View File

@ -5415,17 +5415,6 @@
mirror: once
do_not_use_directly: true
- name: layers.advanced.basic-layer.enabled
type: RelaxedAtomicBool
value: false
mirror: always
# Whether we allow advanced layers with fission
- name: layers.advanced.fission.enabled
type: bool
value: false
mirror: always
# Whether we allow AMD switchable graphics.
- name: layers.amd-switchable-gfx.enabled
type: bool
@ -5705,52 +5694,6 @@
value: -1
mirror: always
- name: layers.mlgpu.enabled
type: bool
value: false
mirror: once
do_not_use_directly: true
- name: layers.mlgpu.enable-buffer-cache
type: bool
value: true
mirror: once
- name: layers.mlgpu.enable-buffer-sharing
type: bool
value: true
mirror: once
- name: layers.mlgpu.enable-clear-view
type: bool
value: true
mirror: once
- name: layers.mlgpu.enable-cpu-occlusion
type: bool
value: true
mirror: once
- name: layers.mlgpu.enable-depth-buffer
type: bool
value: false
mirror: once
- name: layers.mlgpu.enable-invalidation
type: RelaxedAtomicBool
value: true
mirror: always
# Both this and the master "enabled" pref must be on to use Advanced Layers
# on Windows 7.
- name: layers.mlgpu.enable-on-windows7
type: bool
#if defined(XP_WIN)
value: true
#else
value: false
#endif
mirror: once
# Whether to animate simple opacity and transforms on the compositor.
- name: layers.offmainthreadcomposition.async-animations

View File

@ -22,14 +22,11 @@ const VIDEO_HEIGHT = 132;
const DRIVER_PREF = "sanity-test.driver-version";
const DEVICE_PREF = "sanity-test.device-id";
const VERSION_PREF = "sanity-test.version";
const ADVANCED_LAYERS_PREF = "sanity-test.advanced-layers";
const WEBRENDER_DISABLED_PREF = "sanity-test.webrender.force-disabled";
const DISABLE_VIDEO_PREF = "media.hardware-video-decoding.failed";
const RUNNING_PREF = "sanity-test.running";
const TIMEOUT_SEC = 20;
const AL_ENABLED_PREF = "layers.mlgpu.enabled";
const AL_TEST_FAILED_PREF = "layers.mlgpu.sanity-test-failed";
const WR_DISABLED_PREF = "gfx.webrender.force-disabled";
// GRAPHICS_SANITY_TEST histogram enumeration values
@ -44,7 +41,6 @@ const REASON_FIRST_RUN = 0;
const REASON_FIREFOX_CHANGED = 1;
const REASON_DEVICE_CHANGED = 2;
const REASON_DRIVER_CHANGED = 3;
const REASON_AL_CONFIG_CHANGED = 4;
const REASON_WR_CONFIG_CHANGED = 5;
function testPixel(ctx, x, y, r, g, b, a, fuzz) {
@ -210,11 +206,7 @@ function verifyLayersRendering(ctx) {
function testCompositor(test, win, ctx) {
if (win.windowUtils.layerManagerType.startsWith("WebRender")) {
// When layer manger type is WebRender, drawWindow() is skipped, since
// drawWindow() could take long time and
// advanced layer is disabled from fallback candidate.
if (Services.prefs.getBoolPref(AL_ENABLED_PREF, false)) {
Services.prefs.setBoolPref(AL_TEST_FAILED_PREF, true);
}
// drawWindow() could take long time.
reportResult(TEST_PASSED);
return true;
}
@ -223,25 +215,12 @@ function testCompositor(test, win, ctx) {
var testPassed = true;
if (!verifyLayersRendering(ctx)) {
// Try disabling advanced layers if it was enabled. Also trigger
// a device reset so the screen redraws.
if (Services.prefs.getBoolPref(AL_ENABLED_PREF, false)) {
Services.prefs.setBoolPref(AL_TEST_FAILED_PREF, true);
// Do not need to reset device when WebRender is used.
// When WebRender is used, advanced layers are not used.
if (test.utils.layerManagerType != "WebRender") {
test.utils.triggerDeviceReset();
}
}
reportResult(TEST_FAILED_RENDER);
testPassed = false;
} else {
Services.prefs.setBoolPref(AL_TEST_FAILED_PREF, false);
if (!verifyVideoRendering(ctx)) {
reportResult(TEST_FAILED_VIDEO);
Services.prefs.setBoolPref(DISABLE_VIDEO_PREF, true);
testPassed = false;
}
} else if (!verifyVideoRendering(ctx)) {
reportResult(TEST_FAILED_VIDEO);
Services.prefs.setBoolPref(DISABLE_VIDEO_PREF, true);
testPassed = false;
}
if (testPassed) {
@ -357,7 +336,6 @@ SanityTest.prototype = {
// gpu or drivers.
var buildId = Services.appinfo.platformBuildID;
var gfxinfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
var hasAL = Services.prefs.getBoolPref(AL_ENABLED_PREF, false);
var disableWR = Services.prefs.getBoolPref(WR_DISABLED_PREF, false);
if (Services.prefs.getBoolPref(RUNNING_PREF, false)) {
@ -408,7 +386,6 @@ SanityTest.prototype = {
) &&
checkPref(DEVICE_PREF, gfxinfo.adapterDeviceID, REASON_DEVICE_CHANGED) &&
checkPref(VERSION_PREF, buildId, REASON_FIREFOX_CHANGED) &&
checkPref(ADVANCED_LAYERS_PREF, hasAL, REASON_AL_CONFIG_CHANGED) &&
checkPref(WEBRENDER_DISABLED_PREF, disableWR, REASON_WR_CONFIG_CHANGED)
) {
return false;
@ -420,7 +397,6 @@ SanityTest.prototype = {
Services.prefs.setStringPref(DRIVER_PREF, gfxinfo.adapterDriverVersion);
Services.prefs.setStringPref(DEVICE_PREF, gfxinfo.adapterDeviceID);
Services.prefs.setStringPref(VERSION_PREF, buildId);
Services.prefs.setBoolPref(ADVANCED_LAYERS_PREF, hasAL);
Services.prefs.setBoolPref(WEBRENDER_DISABLED_PREF, disableWR);
// Update the prefs so that this test doesn't run again until the next update.

View File

@ -190,9 +190,6 @@ static const char* GetPrefNameForFeature(int32_t aFeature) {
case nsIGfxInfo::FEATURE_WEBGL2:
name = BLOCKLIST_PREF_BRANCH "webgl2";
break;
case nsIGfxInfo::FEATURE_ADVANCED_LAYERS:
name = BLOCKLIST_PREF_BRANCH "layers.advanced";
break;
case nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX:
name = BLOCKLIST_PREF_BRANCH "d3d11.keyed.mutex";
break;
@ -407,8 +404,6 @@ static int32_t BlocklistFeatureToGfxFeature(const nsAString& aFeature) {
return nsIGfxInfo::FEATURE_GPU_PROCESS;
else if (aFeature.EqualsLiteral("WEBGL2"))
return nsIGfxInfo::FEATURE_WEBGL2;
else if (aFeature.EqualsLiteral("ADVANCED_LAYERS"))
return nsIGfxInfo::FEATURE_ADVANCED_LAYERS;
else if (aFeature.EqualsLiteral("D3D11_KEYED_MUTEX"))
return nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX;
else if (aFeature.EqualsLiteral("WEBRENDER"))
@ -1281,7 +1276,6 @@ void GfxInfoBase::EvaluateDownloadedBlocklist(
nsIGfxInfo::FEATURE_DX_INTEROP2,
nsIGfxInfo::FEATURE_GPU_PROCESS,
nsIGfxInfo::FEATURE_WEBGL2,
nsIGfxInfo::FEATURE_ADVANCED_LAYERS,
nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX,
nsIGfxInfo::FEATURE_WEBRENDER,
nsIGfxInfo::FEATURE_WEBRENDER_COMPOSITOR,
@ -1660,18 +1654,6 @@ void GfxInfoBase::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj) {
gfx::FeatureState& omtp = gfxConfig::GetFeature(gfx::Feature::OMTP);
InitFeatureObject(aCx, aObj, "omtp", omtp, &obj);
// Only include AL if the platform attempted to use it.
gfx::FeatureState& advancedLayers =
gfxConfig::GetFeature(gfx::Feature::ADVANCED_LAYERS);
if (advancedLayers.GetValue() != FeatureStatus::Unused) {
InitFeatureObject(aCx, aObj, "advancedLayers", advancedLayers, &obj);
if (gfxConfig::UseFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING)) {
JS::Rooted<JS::Value> trueVal(aCx, JS::BooleanValue(true));
JS_SetProperty(aCx, obj, "noConstantBufferOffsetting", trueVal);
}
}
}
bool GfxInfoBase::InitFeatureObject(JSContext* aCx,

View File

@ -1219,13 +1219,6 @@ already_AddRefed<LayerManager> nsBaseWidget::CreateCompositorSession(
bool enableAPZ = UseAPZ();
CompositorOptions options(enableAPZ, enableWR);
// Bug 1588484 - Advanced Layers is currently disabled for fission windows,
// since it doesn't properly support nested RefLayers.
bool enableAL =
gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS) &&
(!mFissionWindow || StaticPrefs::layers_advanced_fission_enabled());
options.SetUseAdvancedLayers(enableAL);
#ifdef MOZ_WIDGET_ANDROID
if (!GetNativeData(NS_JAVA_SURFACE)) {
options.SetInitiallyPaused(true);

View File

@ -151,28 +151,26 @@ interface nsIGfxInfo : nsISupports
const long FEATURE_GPU_PROCESS = 20;
/* Whether the WebGL2 is supported, starting in 54 */
const long FEATURE_WEBGL2 = 21;
/* Whether Advanced Layers is supported, starting in 56 */
const long FEATURE_ADVANCED_LAYERS = 22;
/* Whether D3D11 keyed mutex is supported, starting in 56 */
const long FEATURE_D3D11_KEYED_MUTEX = 23;
const long FEATURE_D3D11_KEYED_MUTEX = 22;
/* Whether WebRender is supported, starting in 62 */
const long FEATURE_WEBRENDER = 24;
const long FEATURE_WEBRENDER = 23;
/* Whether WebRender is supported, starting in 62 */
const long FEATURE_DX_NV12 = 25;
const long FEATURE_DX_P010 = 26;
const long FEATURE_DX_P016 = 27;
const long FEATURE_DX_NV12 = 24;
const long FEATURE_DX_P010 = 25;
const long FEATURE_DX_P016 = 26;
/* Whether OpenGL swizzle configuration of texture units is supported, starting in 70 */
const long FEATURE_GL_SWIZZLE = 28;
const long FEATURE_GL_SWIZZLE = 27;
/* Whether WebRender native compositor is supported, starting in 73 */
const long FEATURE_WEBRENDER_COMPOSITOR = 29;
const long FEATURE_WEBRENDER_COMPOSITOR = 28;
/* Whether WebRender can use scissored clears for cached surfaces, staring in 79 */
const long FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS = 30;
const long FEATURE_WEBRENDER_SCISSORED_CACHE_CLEARS = 29;
/* Support webgl.out-of-process: true (starting in 83) */
const long FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS = 31;
const long FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS = 30;
/* Is OpenGL threadsafe (starting in 83) */
const long FEATURE_THREADSAFE_GL = 32;
const long FEATURE_THREADSAFE_GL = 31;
/* Support running WebRender using the software backend, starting in 84. */
const long FEATURE_WEBRENDER_SOFTWARE = 33;
const long FEATURE_WEBRENDER_SOFTWARE = 32;
/* the maximum feature value. */
const long FEATURE_MAX_VALUE = FEATURE_WEBRENDER_SOFTWARE;

View File

@ -1729,14 +1729,6 @@ const nsTArray<GfxDriverInfo>& GfxInfo::GetGfxDriverInfo() {
nsIGfxInfo::FEATURE_BLOCKED_DEVICE, DRIVER_LESS_THAN,
GfxDriverInfo::allDriverVersions, "FEATURE_FAILURE_BUG_1359416");
// bug 1419264
APPEND_TO_DRIVER_BLOCKLIST_RANGE(
OperatingSystem::Windows7, DeviceFamily::NvidiaAll,
nsIGfxInfo::FEATURE_ADVANCED_LAYERS,
nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION, DRIVER_BETWEEN_INCLUSIVE,
V(23, 21, 13, 8569), V(23, 21, 13, 9135), "FEATURE_FAILURE_BUG_1419264",
"Windows 10");
// Bug 1447141, for causing device creation crashes.
APPEND_TO_DRIVER_BLOCKLIST2(
OperatingSystem::Windows7, DeviceFamily::Bug1447141,