mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Initial import of Advanced Layers. (bug 1365879 part 20, r=bas)
This commit is contained in:
parent
3115836c5c
commit
6376e2c6bb
313
gfx/doc/AdvancedLayers.md
Normal file
313
gfx/doc/AdvancedLayers.md
Normal file
@ -0,0 +1,313 @@
|
||||
Advanced Layers
|
||||
==============
|
||||
|
||||
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 basic 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 vertex (in a triangle list), and any
|
||||
ancillary data needed for the pixel shader. Often this ancillary data is just an index into
|
||||
a constant buffer (more on this below).
|
||||
|
||||
The vertex shader applies transforms and sends data down to the pixel shader, which performs
|
||||
clipping and masking.
|
||||
|
||||
Most of the time, layers have simple rectangular clips with simple rectilinear transforms, and
|
||||
pixel shaders do not need to perform masking or clipping. We take advantage of this for common
|
||||
layer types, and use a second set of vertex and pixel shaders. These shaders have a unified
|
||||
input layout: a draw rect, a layers ID, and a z-buffer depth. The pipeline uses a unit quad
|
||||
as input. Ancillary data is stored in a constant buffer, which is indexed by the instance ID.
|
||||
This path performs clipping in the vertex shader, and the pixel shader does not support masks.
|
||||
|
||||
Most shader types use ancillary data (such as texture coordinates, or a color value). This is
|
||||
stored in a constant buffer, which is bound to the vertex shader. Unit quad shaders use
|
||||
instancing to access the buffer. Full-fledged, triangle list shaders store the index in each
|
||||
vertex.
|
||||
|
||||
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 coordiantes).
|
||||
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.
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/gfx/Polygon.h"
|
||||
#include "nsRegion.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "mozilla/layers/APZChild.h"
|
||||
#include "nsIContentInlines.h"
|
||||
|
||||
#include "InputData.h" // for InputData
|
||||
|
||||
|
@ -63,6 +63,8 @@ class TextRenderer;
|
||||
class CompositingRenderTarget;
|
||||
struct FPSState;
|
||||
class PaintCounter;
|
||||
class LayerMLGPU;
|
||||
class LayerManagerMLGPU;
|
||||
class UiCompositorControllerParent;
|
||||
|
||||
static const int kVisualWarningDuration = 150; // ms
|
||||
@ -123,6 +125,9 @@ public:
|
||||
virtual HostLayerManager* AsHostLayerManager() override {
|
||||
return this;
|
||||
}
|
||||
virtual LayerManagerMLGPU* AsLayerManagerMLGPU() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
|
||||
{
|
||||
@ -550,6 +555,8 @@ public:
|
||||
|
||||
virtual Layer* GetLayer() = 0;
|
||||
|
||||
virtual LayerMLGPU* AsLayerMLGPU() { return nullptr; }
|
||||
|
||||
virtual bool SetCompositableHost(CompositableHost*)
|
||||
{
|
||||
// We must handle this gracefully, see bug 967824
|
||||
@ -569,6 +576,10 @@ public:
|
||||
{
|
||||
mShadowVisibleRegion = aRegion;
|
||||
}
|
||||
void SetShadowVisibleRegion(LayerIntRegion&& aRegion)
|
||||
{
|
||||
mShadowVisibleRegion = Move(aRegion);
|
||||
}
|
||||
|
||||
void SetShadowOpacity(float aOpacity)
|
||||
{
|
||||
@ -596,11 +607,12 @@ public:
|
||||
// These getters can be used anytime.
|
||||
float GetShadowOpacity() { return mShadowOpacity; }
|
||||
const Maybe<ParentLayerIntRect>& GetShadowClipRect() { return mShadowClipRect; }
|
||||
const LayerIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
|
||||
const LayerIntRegion& GetShadowVisibleRegion() const { return mShadowVisibleRegion; }
|
||||
const gfx::Matrix4x4& GetShadowBaseTransform() { return mShadowTransform; }
|
||||
gfx::Matrix4x4 GetShadowTransform();
|
||||
bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
|
||||
bool GetShadowOpacitySetByAnimation() { return mShadowOpacitySetByAnimation; }
|
||||
LayerIntRegion&& GetShadowVisibleRegion() { return Move(mShadowVisibleRegion); }
|
||||
|
||||
protected:
|
||||
HostLayerManager* mCompositorManager;
|
||||
|
@ -47,7 +47,7 @@ using namespace gfx;
|
||||
|
||||
namespace layers {
|
||||
|
||||
static bool CanUsePartialPresents(ID3D11Device* aDevice);
|
||||
bool CanUsePartialPresents(ID3D11Device* aDevice);
|
||||
|
||||
const FLOAT sBlendFactor[] = { 0, 0, 0, 0 };
|
||||
|
||||
@ -255,7 +255,7 @@ CompositorD3D11::Initialize(nsCString* const out_failureReason)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
bool
|
||||
CanUsePartialPresents(ID3D11Device* aDevice)
|
||||
{
|
||||
if (gfxPrefs::PartialPresent() > 0) {
|
||||
|
1921
gfx/layers/d3d11/MLGDeviceD3D11.cpp
Normal file
1921
gfx/layers/d3d11/MLGDeviceD3D11.cpp
Normal file
File diff suppressed because it is too large
Load Diff
330
gfx/layers/d3d11/MLGDeviceD3D11.h
Normal file
330
gfx/layers/d3d11/MLGDeviceD3D11.h
Normal file
@ -0,0 +1,330 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_d3d11_MLGDeviceD3D11_h
|
||||
#define mozilla_gfx_layers_d3d11_MLGDeviceD3D11_h
|
||||
|
||||
#include "mozilla/layers/MLGDevice.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include <d3d11_1.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:
|
||||
~MLGRenderTargetD3D11() override;
|
||||
|
||||
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);
|
||||
~MLGSwapChainD3D11() override;
|
||||
|
||||
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);
|
||||
~MLGBufferD3D11() override;
|
||||
|
||||
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);
|
||||
~MLGDeviceD3D11() override;
|
||||
|
||||
bool Initialize() override;
|
||||
|
||||
void StartDiagnostics(uint32_t aInvalidPixels) override;
|
||||
void EndDiagnostics() override;
|
||||
void GetDiagnostics(GPUStats* aStats) override;
|
||||
|
||||
MLGDeviceD3D11* AsD3D11() override { return this; }
|
||||
TextureFactoryIdentifier GetTextureFactoryIdentifier() 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::Color& aColor) override;
|
||||
void ClearDepthBuffer(MLGRenderTarget* aRT) override;
|
||||
void ClearView(MLGRenderTarget* aRT, const gfx::Color& 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();
|
||||
|
||||
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<IDXGIResource> mSyncTexture;
|
||||
HANDLE mSyncHandle;
|
||||
|
||||
RefPtr<MLGRenderTarget> mCurrentRT;
|
||||
RefPtr<MLGBuffer> mUnitQuadVB;
|
||||
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
|
@ -90,6 +90,14 @@ SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes)
|
||||
{
|
||||
aTexture->SetPrivateDataInterface(
|
||||
sD3D11TextureUsage,
|
||||
new TextureMemoryMeasurer(aBytes));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize)
|
||||
{
|
||||
|
@ -483,6 +483,7 @@ inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel
|
||||
}
|
||||
|
||||
uint32_t GetMaxTextureSizeFromDevice(ID3D11Device* aDevice);
|
||||
void ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes);
|
||||
|
||||
class AutoLockD3D11Texture
|
||||
{
|
||||
|
15
gfx/layers/d3d11/mlgshaders/blend-common.hlsl
Normal file
15
gfx/layers/d3d11/mlgshaders/blend-common.hlsl
Normal file
@ -0,0 +1,15 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
|
||||
struct VS_BLEND_OUTPUT
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
float2 vBackdropCoords : TEXCOORD1;
|
||||
float2 vLocalPos : TEXCOORD2;
|
||||
float3 vMaskCoords : TEXCOORD3;
|
||||
nointerpolation float4 vClipRect : TEXCOORD4;
|
||||
};
|
540
gfx/layers/d3d11/mlgshaders/blend-ps-generated.hlslh
Normal file
540
gfx/layers/d3d11/mlgshaders/blend-ps-generated.hlslh
Normal file
@ -0,0 +1,540 @@
|
||||
float4 BlendMultiplyPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendMultiply(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendScreenPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendScreen(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendOverlayPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendOverlay(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendDarkenPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendDarken(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendLightenPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendLighten(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendColorDodgePS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendColorDodge(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendColorBurnPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendColorBurn(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendHardLightPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= sOpacity;
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendHardLight(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendSoftLightPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendSoftLight(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendDifferencePS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendDifference(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendExclusionPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendExclusion(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendHuePS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendHue(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendSaturationPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendSaturation(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendColorPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendColor(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 BlendLuminosityPS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = BlendLuminosity(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
||||
|
36
gfx/layers/d3d11/mlgshaders/blend-ps-generated.hlslh.tpl
Normal file
36
gfx/layers/d3d11/mlgshaders/blend-ps-generated.hlslh.tpl
Normal file
@ -0,0 +1,36 @@
|
||||
float4 Blend{BLEND_FUNC}PS(const VS_BLEND_OUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float4 backdrop = tBackdrop.Sample(sSampler, aInput.vBackdropCoords);
|
||||
float4 source = simpleTex.Sample(sSampler, aInput.vTexCoords);
|
||||
|
||||
// Apply masks to the source texture, not the result.
|
||||
source *= ReadMask(aInput.vMaskCoords);
|
||||
|
||||
// Shortcut when the backdrop or source alpha is 0, otherwise we may leak
|
||||
// infinity into the blend function and return incorrect results.
|
||||
if (backdrop.a == 0.0) {
|
||||
return source;
|
||||
}
|
||||
if (source.a == 0.0) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// The spec assumes there is no premultiplied alpha. The backdrop and
|
||||
// source are both render targets and always premultiplied, so we undo
|
||||
// that here.
|
||||
backdrop.rgb /= backdrop.a;
|
||||
source.rgb /= source.a;
|
||||
|
||||
float4 result;
|
||||
result.rgb = Blend{BLEND_FUNC}(backdrop.rgb, source.rgb);
|
||||
result.a = source.a;
|
||||
|
||||
// Factor backdrop alpha, then premultiply for the final OP_OVER.
|
||||
result.rgb = (1.0 - backdrop.a) * source.rgb + backdrop.a * result.rgb;
|
||||
result.rgb *= result.a;
|
||||
return result;
|
||||
}
|
13
gfx/layers/d3d11/mlgshaders/blend-ps.hlsl
Normal file
13
gfx/layers/d3d11/mlgshaders/blend-ps.hlsl
Normal file
@ -0,0 +1,13 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common.hlsl"
|
||||
#include "common-ps.hlsl"
|
||||
#include "blend-common.hlsl"
|
||||
#include "../BlendingHelpers.hlslh"
|
||||
|
||||
Texture2D simpleTex : register(ps, t0);
|
||||
Texture2D tBackdrop : register(ps, t1);
|
||||
|
||||
#include "blend-ps-generated.hlslh"
|
41
gfx/layers/d3d11/mlgshaders/blend-vs.hlsl
Normal file
41
gfx/layers/d3d11/mlgshaders/blend-vs.hlsl
Normal file
@ -0,0 +1,41 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
#include "blend-common.hlsl"
|
||||
#include "textured-common.hlsl"
|
||||
|
||||
cbuffer BlendConstants : register(b4)
|
||||
{
|
||||
float4x4 mBackdropTransform;
|
||||
}
|
||||
|
||||
float2 BackdropPosition(float4 aPosition)
|
||||
{
|
||||
// Move the position from clip space (-1,1) into 0..1 space.
|
||||
float2 pos;
|
||||
pos.x = (aPosition.x + 1.0) / 2.0;
|
||||
pos.y = 1.0 - (aPosition.y + 1.0) / 2.0;
|
||||
|
||||
return mul(mBackdropTransform, float4(pos.xy, 0, 1.0)).xy;
|
||||
}
|
||||
|
||||
VS_BLEND_OUTPUT BlendImpl(const VertexInfo aInfo, float2 aTexCoord)
|
||||
{
|
||||
VS_BLEND_OUTPUT output;
|
||||
output.vPosition = aInfo.worldPos;
|
||||
output.vTexCoords = aTexCoord;
|
||||
output.vBackdropCoords = BackdropPosition(output.vPosition);
|
||||
output.vLocalPos = aInfo.screenPos;
|
||||
output.vClipRect = aInfo.clipRect;
|
||||
output.vMaskCoords = aInfo.maskCoords;
|
||||
return output;
|
||||
}
|
||||
|
||||
VS_BLEND_OUTPUT BlendVertexVS(const VS_TEXTUREDVERTEX aVertex)
|
||||
{
|
||||
VertexInfo info = ComputePosition(aVertex.vLayerPos, aVertex.vLayerId, aVertex.vDepth);
|
||||
|
||||
return BlendImpl(info, aVertex.vTexCoord);
|
||||
}
|
9
gfx/layers/d3d11/mlgshaders/clear-common.hlsl
Normal file
9
gfx/layers/d3d11/mlgshaders/clear-common.hlsl
Normal file
@ -0,0 +1,9 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
struct VS_CLEAR_OUT
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
};
|
12
gfx/layers/d3d11/mlgshaders/clear-ps.hlsl
Normal file
12
gfx/layers/d3d11/mlgshaders/clear-ps.hlsl
Normal file
@ -0,0 +1,12 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-ps.hlsl"
|
||||
#include "clear-common.hlsl"
|
||||
|
||||
float4 ClearPS(const VS_CLEAR_OUT aVS) : SV_Target
|
||||
{
|
||||
return float4(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
30
gfx/layers/d3d11/mlgshaders/clear-vs.hlsl
Normal file
30
gfx/layers/d3d11/mlgshaders/clear-vs.hlsl
Normal file
@ -0,0 +1,30 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
#include "clear-common.hlsl"
|
||||
|
||||
struct VS_CLEAR_IN
|
||||
{
|
||||
float2 vPos : POSITION;
|
||||
int4 vRect : TEXCOORD0;
|
||||
};
|
||||
|
||||
// Note: we use slot 2 so we don't have to rebind the layer slot (1) to run
|
||||
// this shader.
|
||||
cbuffer ClearConstants : register(b2) {
|
||||
int sDepth : packoffset(c0.x);
|
||||
};
|
||||
|
||||
VS_CLEAR_OUT ClearVS(const VS_CLEAR_IN aInput)
|
||||
{
|
||||
float4 rect = float4(aInput.vRect.x, aInput.vRect.y, aInput.vRect.z, aInput.vRect.w);
|
||||
float4 screenPos = float4(UnitQuadToRect(aInput.vPos, rect), 0, 1);
|
||||
float4 worldPos = mul(WorldTransform, screenPos);
|
||||
worldPos.z = ComputeDepth(worldPos, sDepth);
|
||||
|
||||
VS_CLEAR_OUT output;
|
||||
output.vPosition = worldPos;
|
||||
return output;
|
||||
}
|
19
gfx/layers/d3d11/mlgshaders/color-common.hlsl
Normal file
19
gfx/layers/d3d11/mlgshaders/color-common.hlsl
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
struct VS_COLOROUTPUT
|
||||
{
|
||||
nointerpolation float4 vColor : COLOR0;
|
||||
nointerpolation float4 vClipRect : TEXCOORD0;
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vLocalPos : TEXCOORD1;
|
||||
float3 vMaskCoords : TEXCOORD2;
|
||||
};
|
||||
|
||||
struct VS_COLOROUTPUT_CLIPPED
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
nointerpolation float4 vColor : COLOR0;
|
||||
};
|
20
gfx/layers/d3d11/mlgshaders/color-ps.hlsl
Normal file
20
gfx/layers/d3d11/mlgshaders/color-ps.hlsl
Normal file
@ -0,0 +1,20 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-ps.hlsl"
|
||||
#include "color-common.hlsl"
|
||||
|
||||
float4 ColoredQuadPS(const VS_COLOROUTPUT_CLIPPED aVS) : SV_Target
|
||||
{
|
||||
// Opacity is always 1.0, we premultiply it on the CPU.
|
||||
return aVS.vColor;
|
||||
}
|
||||
|
||||
float4 ColoredVertexPS(const VS_COLOROUTPUT aVS) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aVS.vClipRect, aVS.vPosition.xy)) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
return aVS.vColor * ReadMaskWithOpacity(aVS.vMaskCoords, 1.0);
|
||||
}
|
70
gfx/layers/d3d11/mlgshaders/color-vs.hlsl
Normal file
70
gfx/layers/d3d11/mlgshaders/color-vs.hlsl
Normal file
@ -0,0 +1,70 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
#include "color-common.hlsl"
|
||||
|
||||
struct ColorItem
|
||||
{
|
||||
float4 color;
|
||||
};
|
||||
#define SIZEOF_COLORITEM 1
|
||||
|
||||
ColorItem GetItem(uint aIndex)
|
||||
{
|
||||
uint offset = aIndex * SIZEOF_COLORITEM;
|
||||
ColorItem item;
|
||||
item.color = sItems[offset + 0];
|
||||
return item;
|
||||
}
|
||||
|
||||
struct VS_COLORQUAD
|
||||
{
|
||||
float2 vPos : POSITION;
|
||||
float4 vRect : TEXCOORD0;
|
||||
uint vLayerId : TEXCOORD1;
|
||||
int vDepth : TEXCOORD2;
|
||||
uint vIndex : SV_InstanceID;
|
||||
};
|
||||
|
||||
struct VS_COLORVERTEX
|
||||
{
|
||||
float2 vLayerPos : POSITION;
|
||||
uint vLayerId : TEXCOORD0;
|
||||
int vDepth : TEXCOORD1;
|
||||
uint vIndex : TEXCOORD2;
|
||||
};
|
||||
|
||||
VS_COLOROUTPUT ColorImpl(float4 aColor, const VertexInfo aInfo)
|
||||
{
|
||||
VS_COLOROUTPUT output;
|
||||
output.vPosition = aInfo.worldPos;
|
||||
output.vLocalPos = aInfo.screenPos;
|
||||
output.vColor = aColor;
|
||||
output.vClipRect = aInfo.clipRect;
|
||||
output.vMaskCoords = aInfo.maskCoords;
|
||||
return output;
|
||||
}
|
||||
|
||||
VS_COLOROUTPUT_CLIPPED ColoredQuadVS(const VS_COLORQUAD aInput)
|
||||
{
|
||||
ColorItem item = GetItem(aInput.vIndex);
|
||||
float4 worldPos = ComputeClippedPosition(
|
||||
aInput.vPos,
|
||||
aInput.vRect,
|
||||
aInput.vLayerId,
|
||||
aInput.vDepth);
|
||||
|
||||
VS_COLOROUTPUT_CLIPPED output;
|
||||
output.vPosition = worldPos;
|
||||
output.vColor = item.color;
|
||||
return output;
|
||||
}
|
||||
|
||||
VS_COLOROUTPUT ColoredVertexVS(const VS_COLORVERTEX aInput)
|
||||
{
|
||||
ColorItem item = GetItem(aInput.vIndex);
|
||||
VertexInfo info = ComputePosition(aInput.vLayerPos, aInput.vLayerId, aInput.vDepth);
|
||||
return ColorImpl(item.color, info);
|
||||
}
|
37
gfx/layers/d3d11/mlgshaders/common-ps.hlsl
Normal file
37
gfx/layers/d3d11/mlgshaders/common-ps.hlsl
Normal file
@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common.hlsl"
|
||||
|
||||
sampler sSampler : register(ps, s0);
|
||||
sampler sMaskSampler : register(ps, s1);
|
||||
|
||||
Texture2D tMaskTexture : register(ps, t4);
|
||||
|
||||
cbuffer MaskInformation : register(b0)
|
||||
{
|
||||
float sOpacity : packoffset(c0.x);
|
||||
uint sHasMask : packoffset(c0.y);
|
||||
};
|
||||
|
||||
float2 MaskCoordsToUV(float3 aMaskCoords)
|
||||
{
|
||||
return aMaskCoords.xy / aMaskCoords.z;
|
||||
}
|
||||
|
||||
float ReadMaskWithOpacity(float3 aMaskCoords, float aOpacity)
|
||||
{
|
||||
if (!sHasMask) {
|
||||
return aOpacity;
|
||||
}
|
||||
|
||||
float2 uv = MaskCoordsToUV(aMaskCoords);
|
||||
float r = tMaskTexture.Sample(sMaskSampler, uv).r;
|
||||
return min(aOpacity, r);
|
||||
}
|
||||
|
||||
float ReadMask(float3 aMaskCoords)
|
||||
{
|
||||
return ReadMaskWithOpacity(aMaskCoords, sOpacity);
|
||||
}
|
162
gfx/layers/d3d11/mlgshaders/common-vs.hlsl
Normal file
162
gfx/layers/d3d11/mlgshaders/common-vs.hlsl
Normal file
@ -0,0 +1,162 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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_mlgshaders_common_vs_hlsl
|
||||
#define mozilla_gfx_layers_d3d11_mlgshaders_common_vs_hlsl
|
||||
|
||||
#include "common.hlsl"
|
||||
|
||||
cbuffer VSBufSimple : register(b0)
|
||||
{
|
||||
float4x4 WorldTransform;
|
||||
float2 RenderTargetOffset;
|
||||
int SortIndexOffset;
|
||||
float padding;
|
||||
};
|
||||
|
||||
struct Layer {
|
||||
float4x4 transform;
|
||||
float4 clipRect;
|
||||
uint4 info;
|
||||
};
|
||||
|
||||
cbuffer Layers : register(b1)
|
||||
{
|
||||
Layer sLayers[682];
|
||||
};
|
||||
|
||||
cbuffer Items : register(b2)
|
||||
{
|
||||
float4 sItems[4096];
|
||||
};
|
||||
|
||||
cbuffer MaskRects : register(b3)
|
||||
{
|
||||
float4 sMaskRects[4096];
|
||||
};
|
||||
|
||||
struct VertexInfo {
|
||||
float4 worldPos;
|
||||
float2 screenPos;
|
||||
float3 maskCoords;
|
||||
float4 clipRect;
|
||||
};
|
||||
|
||||
float3 ComputeMaskCoords(float4 aPosition, Layer aLayer)
|
||||
{
|
||||
if (aLayer.info.x == 0) {
|
||||
return float3(0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
float4 maskRect = sMaskRects[aLayer.info.x - 1];
|
||||
|
||||
// See the perspective comment in CompositorD3D11.hlsl.
|
||||
float4x4 transform = float4x4(
|
||||
1.0/maskRect.z, 0.0, 0.0, -maskRect.x/maskRect.z,
|
||||
0.0, 1.0/maskRect.w, 0.0, -maskRect.y/maskRect.w,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
return float3(mul(transform, aPosition / aPosition.w).xy, 1.0) * aPosition.w;
|
||||
}
|
||||
|
||||
float2 UnitQuadToRect(const float2 aVertex, const float4 aRect)
|
||||
{
|
||||
return float2(aRect.x + aVertex.x * aRect.z, aRect.y + aVertex.y * aRect.w);
|
||||
}
|
||||
|
||||
float ComputeDepth(float4 aPosition, float aSortIndex)
|
||||
{
|
||||
// Note: this value should match ShaderDefinitionsMLGPU.h.
|
||||
return ((aSortIndex + SortIndexOffset) / 1000000.0f) * aPosition.w;
|
||||
}
|
||||
|
||||
// Compute the world-space, screen-space, layer-space clip, and mask
|
||||
// uv-coordinates given a layer-space vertex, id, and z-index.
|
||||
VertexInfo ComputePosition(float2 aVertex, uint aLayerId, float aSortIndex)
|
||||
{
|
||||
Layer layer = sLayers[aLayerId];
|
||||
|
||||
// Translate from unit vertex to layer quad vertex.
|
||||
float4 position = float4(aVertex, 0, 1);
|
||||
float4 clipRect = layer.clipRect;
|
||||
|
||||
// Transform to screen coordinates.
|
||||
float4x4 transform = layer.transform;
|
||||
position = mul(transform, position);
|
||||
position.xyz /= position.w;
|
||||
position.xy -= RenderTargetOffset.xy;
|
||||
position.xyz *= position.w;
|
||||
|
||||
float4 worldPos = mul(WorldTransform, position);
|
||||
|
||||
// Depth must be computed after the world transform, since we don't want
|
||||
// 3d transforms clobbering the z-value. We assume a viewport culling
|
||||
// everything outside of [0, 1). Note that when depth-testing, we do not
|
||||
// use sorting indices < 1.
|
||||
//
|
||||
// Note that we have to normalize this value to w=1, since the GPU will
|
||||
// divide all values by w internally.
|
||||
worldPos.z = ComputeDepth(worldPos, aSortIndex);
|
||||
|
||||
VertexInfo info;
|
||||
info.screenPos = position.xy;
|
||||
info.worldPos = worldPos;
|
||||
info.maskCoords = ComputeMaskCoords(position, layer);
|
||||
info.clipRect = clipRect;
|
||||
return info;
|
||||
}
|
||||
|
||||
// This function takes a unit quad position and a layer rectangle, and computes
|
||||
// a clipped draw rect. It is only valid to use this function for layers with
|
||||
// rectilinear transforms that do not have masks.
|
||||
float4 ComputeClippedPosition(const float2 aVertex,
|
||||
const float4 aRect,
|
||||
uint aLayerId,
|
||||
float aDepth)
|
||||
{
|
||||
Layer layer = sLayers[aLayerId];
|
||||
|
||||
float4 position = float4(UnitQuadToRect(aVertex, aRect), 0, 1);
|
||||
|
||||
float4x4 transform = layer.transform;
|
||||
float4 clipRect = layer.clipRect;
|
||||
|
||||
// Transform to screen coordinates.
|
||||
//
|
||||
// We clamp the draw rect to the clip. This lets us use faster shaders.
|
||||
// For opaque shapes, it is necessary to do this anyway since we might
|
||||
// otherwrite write transparent pixels in the pixel which would also be
|
||||
// written to the depth buffer. We cannot use discard in the pixel shader
|
||||
// as this would break early-z tests.
|
||||
//
|
||||
// Note that for some shaders, like textured shaders, it is not valid to
|
||||
// change the draw rect like this without also clamping the texture
|
||||
// coordinates. We take care to adjust for this in our batching code.
|
||||
//
|
||||
// We do not need to do this for 3D transforms since we always treat those
|
||||
// as transparent (they are not written to the depth buffer). 3D items
|
||||
// will always use the full clip+masking shader.
|
||||
position = mul(transform, position);
|
||||
position.xyz /= position.w;
|
||||
position.xy -= RenderTargetOffset.xy;
|
||||
position.xy = clamp(position.xy, clipRect.xy, clipRect.xy + clipRect.zw);
|
||||
position.xyz *= position.w;
|
||||
|
||||
float4 worldPos = mul(WorldTransform, position);
|
||||
|
||||
// Depth must be computed after the world transform, since we don't want
|
||||
// 3d transforms clobbering the z-value. We assume a viewport culling
|
||||
// everything outside of [0, 1). Note that when depth-testing, we do not
|
||||
// use sorting indices < 1.
|
||||
//
|
||||
// Note that we have to normalize this value to w=1, since the GPU will
|
||||
// divide all values by w internally.
|
||||
worldPos.z = ComputeDepth(worldPos, aDepth);
|
||||
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
#endif // mozilla_gfx_layers_d3d11_mlgshaders_common_vs_hlsl
|
17
gfx/layers/d3d11/mlgshaders/common.hlsl
Normal file
17
gfx/layers/d3d11/mlgshaders/common.hlsl
Normal file
@ -0,0 +1,17 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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_mlgshaders_common_hlsl
|
||||
#define mozilla_gfx_layers_d3d11_mlgshaders_common_hlsl
|
||||
|
||||
bool RectContainsPoint(float4 aRect, float2 aPoint)
|
||||
{
|
||||
return aPoint.x >= aRect.x &&
|
||||
aPoint.y >= aRect.y &&
|
||||
aPoint.x <= (aRect.x + aRect.z) &&
|
||||
aPoint.y <= (aRect.y + aRect.w);
|
||||
}
|
||||
|
||||
#endif // mozilla_gfx_layers_d3d11_mlgshaders_common_hlsl
|
45
gfx/layers/d3d11/mlgshaders/component-alpha-ps.hlsl
Normal file
45
gfx/layers/d3d11/mlgshaders/component-alpha-ps.hlsl
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common.hlsl"
|
||||
#include "common-ps.hlsl"
|
||||
#include "textured-common.hlsl"
|
||||
|
||||
Texture2D texOnBlack : register(ps, t0);
|
||||
Texture2D texOnWhite : register(ps, t1);
|
||||
|
||||
struct PS_OUTPUT {
|
||||
float4 vSrc;
|
||||
float4 vAlpha;
|
||||
};
|
||||
|
||||
PS_OUTPUT ComponentAlphaQuadPS(const VS_SAMPLEOUTPUT_CLIPPED aInput) : SV_Target
|
||||
{
|
||||
PS_OUTPUT result;
|
||||
result.vSrc = texOnBlack.Sample(sSampler, aInput.vTexCoords);
|
||||
result.vAlpha = 1.0 - texOnWhite.Sample(sSampler, aInput.vTexCoords) + result.vSrc;
|
||||
result.vSrc.a = result.vAlpha.g;
|
||||
result.vSrc *= sOpacity;
|
||||
result.vAlpha *= sOpacity;
|
||||
return result;
|
||||
}
|
||||
|
||||
PS_OUTPUT ComponentAlphaVertexPS(const VS_SAMPLEOUTPUT aInput) : SV_Target
|
||||
{
|
||||
PS_OUTPUT result;
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
result.vSrc = float4(0, 0, 0, 0);
|
||||
result.vAlpha = float4(0, 0, 0, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
float alpha = ReadMask(aInput.vMaskCoords);
|
||||
|
||||
result.vSrc = texOnBlack.Sample(sSampler, aInput.vTexCoords);
|
||||
result.vAlpha = 1.0 - texOnWhite.Sample(sSampler, aInput.vTexCoords) + result.vSrc;
|
||||
result.vSrc.a = result.vAlpha.g;
|
||||
result.vSrc *= alpha;
|
||||
result.vAlpha *= alpha;
|
||||
return result;
|
||||
}
|
10
gfx/layers/d3d11/mlgshaders/diagnostics-common.hlsl
Normal file
10
gfx/layers/d3d11/mlgshaders/diagnostics-common.hlsl
Normal file
@ -0,0 +1,10 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
struct VS_DIAGOUTPUT
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoord : TEXCOORD0;
|
||||
};
|
13
gfx/layers/d3d11/mlgshaders/diagnostics-ps.hlsl
Normal file
13
gfx/layers/d3d11/mlgshaders/diagnostics-ps.hlsl
Normal file
@ -0,0 +1,13 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-ps.hlsl"
|
||||
#include "diagnostics-common.hlsl"
|
||||
|
||||
Texture2D sTexture: register(ps, t0);
|
||||
|
||||
float4 DiagnosticTextPS(const VS_DIAGOUTPUT aInput) : SV_Target
|
||||
{
|
||||
return sTexture.Sample(sSampler, aInput.vTexCoord);
|
||||
}
|
25
gfx/layers/d3d11/mlgshaders/diagnostics-vs.hlsl
Normal file
25
gfx/layers/d3d11/mlgshaders/diagnostics-vs.hlsl
Normal file
@ -0,0 +1,25 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
#include "textured-common.hlsl"
|
||||
#include "diagnostics-common.hlsl"
|
||||
|
||||
struct VS_DIAGINPUT
|
||||
{
|
||||
float2 vPos : POSITION;
|
||||
float4 vRect : TEXCOORD0;
|
||||
float4 vTexCoords : TEXCOORD1;
|
||||
};
|
||||
|
||||
VS_DIAGOUTPUT DiagnosticTextVS(const VS_DIAGINPUT aInput)
|
||||
{
|
||||
float2 pos = UnitQuadToRect(aInput.vPos, aInput.vRect);
|
||||
float2 texCoord = UnitQuadToRect(aInput.vPos, aInput.vTexCoords);
|
||||
|
||||
VS_DIAGOUTPUT output;
|
||||
output.vPosition = mul(WorldTransform, float4(pos, 0, 1));
|
||||
output.vTexCoord = texCoord;
|
||||
return output;
|
||||
}
|
10
gfx/layers/d3d11/mlgshaders/mask-combiner-common.hlsl
Normal file
10
gfx/layers/d3d11/mlgshaders/mask-combiner-common.hlsl
Normal file
@ -0,0 +1,10 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
struct VS_MASKOUTPUT
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
};
|
16
gfx/layers/d3d11/mlgshaders/mask-combiner-ps.hlsl
Normal file
16
gfx/layers/d3d11/mlgshaders/mask-combiner-ps.hlsl
Normal file
@ -0,0 +1,16 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common.hlsl"
|
||||
#include "mask-combiner-common.hlsl"
|
||||
|
||||
sampler sSampler;
|
||||
|
||||
Texture2D tMaskTexture : register(ps, t0);
|
||||
|
||||
float4 MaskCombinerPS(VS_MASKOUTPUT aInput) : SV_Target
|
||||
{
|
||||
float4 value = tMaskTexture.Sample(sSampler, aInput.vTexCoords);
|
||||
return float4(value.r, 0, 0, value.r);
|
||||
}
|
26
gfx/layers/d3d11/mlgshaders/mask-combiner-vs.hlsl
Normal file
26
gfx/layers/d3d11/mlgshaders/mask-combiner-vs.hlsl
Normal file
@ -0,0 +1,26 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
#include "mask-combiner-common.hlsl"
|
||||
|
||||
struct VS_MASKINPUT
|
||||
{
|
||||
// Note, the input is
|
||||
float2 vPos : POSITION;
|
||||
float4 vTexCoords : POSITION1;
|
||||
};
|
||||
|
||||
VS_MASKOUTPUT MaskCombinerVS(VS_MASKINPUT aInput)
|
||||
{
|
||||
float4 position = float4(
|
||||
aInput.vPos.x * 2.0f - 1.0f,
|
||||
1.0f - (aInput.vPos.y * 2.0f),
|
||||
0, 1);
|
||||
|
||||
VS_MASKOUTPUT output;
|
||||
output.vPosition = position;
|
||||
output.vTexCoords = UnitQuadToRect(aInput.vPos, aInput.vTexCoords);
|
||||
return output;
|
||||
}
|
94
gfx/layers/d3d11/mlgshaders/shaders.manifest
Normal file
94
gfx/layers/d3d11/mlgshaders/shaders.manifest
Normal file
@ -0,0 +1,94 @@
|
||||
- type: vs_4_0
|
||||
file: textured-vs.hlsl
|
||||
shaders:
|
||||
- TexturedQuadVS
|
||||
- TexturedVertexVS
|
||||
|
||||
- type: ps_4_0
|
||||
file: textured-ps.hlsl
|
||||
shaders:
|
||||
- TexturedVertexRGB
|
||||
- TexturedVertexRGBA
|
||||
- TexturedQuadRGB
|
||||
- TexturedQuadRGBA
|
||||
|
||||
- type: ps_4_0
|
||||
file: ycbcr-ps.hlsl
|
||||
shaders:
|
||||
- TexturedVertexIMC4
|
||||
- TexturedVertexNV12
|
||||
- TexturedQuadIMC4
|
||||
- TexturedQuadNV12
|
||||
|
||||
- type: vs_4_0
|
||||
file: color-vs.hlsl
|
||||
shaders:
|
||||
- ColoredQuadVS
|
||||
- ColoredVertexVS
|
||||
|
||||
- type: ps_4_0
|
||||
file: color-ps.hlsl
|
||||
shaders:
|
||||
- ColoredQuadPS
|
||||
- ColoredVertexPS
|
||||
|
||||
- type: ps_4_0
|
||||
file: component-alpha-ps.hlsl
|
||||
shaders:
|
||||
- ComponentAlphaQuadPS
|
||||
- ComponentAlphaVertexPS
|
||||
|
||||
- type: vs_4_0
|
||||
file: blend-vs.hlsl
|
||||
shaders:
|
||||
- BlendVertexVS
|
||||
|
||||
- type: ps_4_0
|
||||
file: blend-ps.hlsl
|
||||
shaders:
|
||||
- BlendMultiplyPS
|
||||
- BlendScreenPS
|
||||
- BlendOverlayPS
|
||||
- BlendDarkenPS
|
||||
- BlendLightenPS
|
||||
- BlendColorDodgePS
|
||||
- BlendColorBurnPS
|
||||
- BlendHardLightPS
|
||||
- BlendSoftLightPS
|
||||
- BlendDifferencePS
|
||||
- BlendExclusionPS
|
||||
- BlendHuePS
|
||||
- BlendSaturationPS
|
||||
- BlendColorPS
|
||||
- BlendLuminosityPS
|
||||
|
||||
- type: vs_4_0
|
||||
file: clear-vs.hlsl
|
||||
shaders:
|
||||
- ClearVS
|
||||
|
||||
- type: ps_4_0
|
||||
file: clear-ps.hlsl
|
||||
shaders:
|
||||
- ClearPS
|
||||
|
||||
- type: vs_4_0
|
||||
file: mask-combiner-vs.hlsl
|
||||
shaders:
|
||||
- MaskCombinerVS
|
||||
|
||||
- type: ps_4_0
|
||||
file: mask-combiner-ps.hlsl
|
||||
shaders:
|
||||
- MaskCombinerPS
|
||||
|
||||
- type: vs_4_0
|
||||
file: diagnostics-vs.hlsl
|
||||
shaders:
|
||||
- DiagnosticTextVS
|
||||
|
||||
- type: ps_4_0
|
||||
file: diagnostics-ps.hlsl
|
||||
shaders:
|
||||
- DiagnosticTextPS
|
||||
|
54
gfx/layers/d3d11/mlgshaders/textured-common.hlsl
Normal file
54
gfx/layers/d3d11/mlgshaders/textured-common.hlsl
Normal file
@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
struct TexturedItem
|
||||
{
|
||||
float4 texCoords;
|
||||
};
|
||||
#define SIZEOF_TEXTUREDITEM 1
|
||||
|
||||
TexturedItem GetItem(uint aIndex)
|
||||
{
|
||||
uint offset = aIndex * SIZEOF_TEXTUREDITEM;
|
||||
TexturedItem item;
|
||||
item.texCoords = sItems[offset + 0];
|
||||
return item;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Instanced version.
|
||||
struct VS_TEXTUREDINPUT
|
||||
{
|
||||
float2 vPos : POSITION;
|
||||
float4 vRect : TEXCOORD0;
|
||||
uint vLayerId : TEXCOORD1;
|
||||
int vDepth : TEXCOORD2;
|
||||
uint vIndex : SV_InstanceID;
|
||||
};
|
||||
|
||||
// Non-instanced version.
|
||||
struct VS_TEXTUREDVERTEX
|
||||
{
|
||||
float2 vLayerPos : POSITION;
|
||||
float2 vTexCoord : TEXCOORD0;
|
||||
uint vLayerId : TEXCOORD1;
|
||||
int vDepth : TEXCOORD2;
|
||||
};
|
||||
|
||||
struct VS_SAMPLEOUTPUT
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
float2 vLocalPos : TEXCOORD1;
|
||||
float3 vMaskCoords : TEXCOORD2;
|
||||
nointerpolation float4 vClipRect : TEXCOORD3;
|
||||
};
|
||||
|
||||
struct VS_SAMPLEOUTPUT_CLIPPED
|
||||
{
|
||||
float4 vPosition : SV_Position;
|
||||
float2 vTexCoords : TEXCOORD0;
|
||||
};
|
45
gfx/layers/d3d11/mlgshaders/textured-ps.hlsl
Normal file
45
gfx/layers/d3d11/mlgshaders/textured-ps.hlsl
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common.hlsl"
|
||||
#include "common-ps.hlsl"
|
||||
#include "textured-common.hlsl"
|
||||
|
||||
Texture2D simpleTex : register(ps, t0);
|
||||
|
||||
float4 FixRGBOpacity(float4 color, float alpha) {
|
||||
return float4(color.rgb * alpha, alpha);
|
||||
}
|
||||
|
||||
// Fast cases that don't require complex clipping.
|
||||
float4 TexturedQuadRGBA(const VS_SAMPLEOUTPUT_CLIPPED aInput) : SV_Target
|
||||
{
|
||||
return simpleTex.Sample(sSampler, aInput.vTexCoords) * sOpacity;
|
||||
}
|
||||
float4 TexturedQuadRGB(const VS_SAMPLEOUTPUT_CLIPPED aInput) : SV_Target
|
||||
{
|
||||
return FixRGBOpacity(simpleTex.Sample(sSampler, aInput.vTexCoords), sOpacity);
|
||||
}
|
||||
|
||||
// PaintedLayer common case.
|
||||
float4 TexturedVertexRGBA(const VS_SAMPLEOUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
float alpha = ReadMask(aInput.vMaskCoords);
|
||||
return simpleTex.Sample(sSampler, aInput.vTexCoords) * alpha;
|
||||
}
|
||||
|
||||
// ImageLayers.
|
||||
float4 TexturedVertexRGB(const VS_SAMPLEOUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
float alpha = ReadMask(aInput.vMaskCoords);
|
||||
return FixRGBOpacity(simpleTex.Sample(sSampler, aInput.vTexCoords), alpha);
|
||||
}
|
40
gfx/layers/d3d11/mlgshaders/textured-vs.hlsl
Normal file
40
gfx/layers/d3d11/mlgshaders/textured-vs.hlsl
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-vs.hlsl"
|
||||
#include "textured-common.hlsl"
|
||||
|
||||
VS_SAMPLEOUTPUT TexturedQuadImpl(const VertexInfo aInfo, const float2 aTexCoord)
|
||||
{
|
||||
VS_SAMPLEOUTPUT output;
|
||||
output.vPosition = aInfo.worldPos;
|
||||
output.vTexCoords = aTexCoord;
|
||||
output.vLocalPos = aInfo.screenPos;
|
||||
output.vClipRect = aInfo.clipRect;
|
||||
output.vMaskCoords = aInfo.maskCoords;
|
||||
return output;
|
||||
}
|
||||
|
||||
VS_SAMPLEOUTPUT_CLIPPED TexturedQuadVS(const VS_TEXTUREDINPUT aVertex)
|
||||
{
|
||||
TexturedItem item = GetItem(aVertex.vIndex);
|
||||
|
||||
float4 worldPos = ComputeClippedPosition(
|
||||
aVertex.vPos,
|
||||
aVertex.vRect,
|
||||
aVertex.vLayerId,
|
||||
aVertex.vDepth);
|
||||
|
||||
VS_SAMPLEOUTPUT_CLIPPED output;
|
||||
output.vPosition = worldPos;
|
||||
output.vTexCoords = UnitQuadToRect(aVertex.vPos, item.texCoords);
|
||||
return output;
|
||||
}
|
||||
|
||||
VS_SAMPLEOUTPUT TexturedVertexVS(const VS_TEXTUREDVERTEX aVertex)
|
||||
{
|
||||
VertexInfo info = ComputePosition(aVertex.vLayerPos, aVertex.vLayerId, aVertex.vDepth);
|
||||
|
||||
return TexturedQuadImpl(info, aVertex.vTexCoord);
|
||||
}
|
91
gfx/layers/d3d11/mlgshaders/ycbcr-ps.hlsl
Normal file
91
gfx/layers/d3d11/mlgshaders/ycbcr-ps.hlsl
Normal file
@ -0,0 +1,91 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* 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 "common-ps.hlsl"
|
||||
#include "textured-common.hlsl"
|
||||
|
||||
Texture2D tY : register(ps, t0);
|
||||
Texture2D tCb : register(ps, t1);
|
||||
Texture2D tCr : register(ps, t2);
|
||||
|
||||
cbuffer YCbCrBuffer : register(b1) {
|
||||
row_major float3x3 YuvColorMatrix;
|
||||
};
|
||||
|
||||
/* From Rec601:
|
||||
[R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
|
||||
[G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
|
||||
[B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
|
||||
|
||||
For [0,1] instead of [0,255], and to 5 places:
|
||||
[R] [1.16438, 0.00000, 1.59603] [ Y - 0.06275]
|
||||
[G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
|
||||
[B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
|
||||
|
||||
From Rec709:
|
||||
[R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [ Y - 16]
|
||||
[G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444] x [Cb - 128]
|
||||
[B] [1.1643835616438356, 2.1124017857142854, 0.0] [Cr - 128]
|
||||
|
||||
For [0,1] instead of [0,255], and to 5 places:
|
||||
[R] [1.16438, 0.00000, 1.79274] [ Y - 0.06275]
|
||||
[G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
|
||||
[B] [1.16438, 2.11240, 0.00000] [Cr - 0.50196]
|
||||
*/
|
||||
float4 CalculateYCbCrColor(float3 rgb)
|
||||
{
|
||||
return float4(
|
||||
mul(YuvColorMatrix,
|
||||
float3(
|
||||
rgb.r - 0.06275,
|
||||
rgb.g - 0.50196,
|
||||
rgb.b - 0.50196)),
|
||||
1.0);
|
||||
}
|
||||
|
||||
float4 CalculateIMC4Color(const float2 aTexCoords)
|
||||
{
|
||||
float3 yuv = float3(
|
||||
tY.Sample(sSampler, aTexCoords).r,
|
||||
tCb.Sample(sSampler, aTexCoords).r,
|
||||
tCr.Sample(sSampler, aTexCoords).r);
|
||||
return CalculateYCbCrColor(yuv);
|
||||
}
|
||||
|
||||
float4 CalculateNV12Color(const float2 aTexCoords)
|
||||
{
|
||||
float y = tY.Sample(sSampler, aTexCoords).r;
|
||||
float2 cbcr = tCb.Sample(sSampler, aTexCoords).rg;
|
||||
return CalculateYCbCrColor(float3(y, cbcr));
|
||||
}
|
||||
|
||||
float4 TexturedQuadIMC4(const VS_SAMPLEOUTPUT_CLIPPED aInput) : SV_Target
|
||||
{
|
||||
return CalculateIMC4Color(aInput.vTexCoords) * sOpacity;
|
||||
}
|
||||
|
||||
float4 TexturedQuadNV12(const VS_SAMPLEOUTPUT_CLIPPED aInput) : SV_Target
|
||||
{
|
||||
return CalculateNV12Color(aInput.vTexCoords) * sOpacity;
|
||||
}
|
||||
|
||||
float4 TexturedVertexIMC4(const VS_SAMPLEOUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
float alpha = ReadMask(aInput.vMaskCoords);
|
||||
return CalculateIMC4Color(aInput.vTexCoords) * alpha;
|
||||
}
|
||||
|
||||
float4 TexturedVertexNV12(const VS_SAMPLEOUTPUT aInput) : SV_Target
|
||||
{
|
||||
if (!RectContainsPoint(aInput.vClipRect, aInput.vPosition.xy)) {
|
||||
return float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
float alpha = ReadMask(aInput.vMaskCoords);
|
||||
return CalculateNV12Color(aInput.vTexCoords) * alpha;
|
||||
}
|
127
gfx/layers/mlgpu/BufferCache.cpp
Normal file
127
gfx/layers/mlgpu/BufferCache.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BufferCache.h"
|
||||
#include "MLGDevice.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
BufferCache::BufferCache(MLGDevice* aDevice)
|
||||
: mDevice(aDevice)
|
||||
{
|
||||
}
|
||||
|
||||
BufferCache::~BufferCache()
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<MLGBuffer>
|
||||
BufferCache::GetOrCreateBuffer(size_t aBytes)
|
||||
{
|
||||
// Try to take a buffer from the expired frame. If none exists, make a new one.
|
||||
RefPtr<MLGBuffer> buffer = mExpired.Take(aBytes);
|
||||
if (!buffer) {
|
||||
// Round up to the nearest size class, but not over 1024 bytes.
|
||||
size_t roundedUp = std::max(std::min(RoundUpPow2(aBytes), size_t(1024)), aBytes);
|
||||
buffer = mDevice->CreateBuffer(MLGBufferType::Constant, roundedUp, MLGUsage::Dynamic, nullptr);
|
||||
if (!buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(buffer->GetSize() >= aBytes);
|
||||
|
||||
// Assign this buffer to the current frame, so it becomes available again once
|
||||
// this frame expires.
|
||||
mCurrent.Put(buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void
|
||||
BufferCache::EndFrame()
|
||||
{
|
||||
BufferPool empty;
|
||||
mExpired = Move(mPrevious);
|
||||
mPrevious = Move(mCurrent);
|
||||
mCurrent = Move(empty);
|
||||
}
|
||||
|
||||
RefPtr<MLGBuffer>
|
||||
BufferPool::Take(size_t aBytes)
|
||||
{
|
||||
MOZ_ASSERT(aBytes >= 16);
|
||||
|
||||
// We need to bump the request up to the nearest size class. For example,
|
||||
// a request of 24 bytes must allocate from the 32 byte pool.
|
||||
SizeClass sc = GetSizeClassFromHighBit(CeilingLog2(aBytes));
|
||||
if (sc == SizeClass::Huge) {
|
||||
return TakeHugeBuffer(aBytes);
|
||||
}
|
||||
|
||||
if (mClasses[sc].IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<MLGBuffer> buffer = mClasses[sc].LastElement();
|
||||
mClasses[sc].RemoveElementAt(mClasses[sc].Length() - 1);
|
||||
return buffer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BufferPool::Put(MLGBuffer* aBuffer)
|
||||
{
|
||||
MOZ_ASSERT(aBuffer->GetSize() >= 16);
|
||||
|
||||
// When returning buffers, we bump them into a lower size class. For example
|
||||
// a 24 byte buffer cannot be re-used for a 32-byte allocation, so it goes
|
||||
// into the 16-byte class.
|
||||
SizeClass sc = GetSizeClassFromHighBit(FloorLog2(aBuffer->GetSize()));
|
||||
if (sc == SizeClass::Huge) {
|
||||
mHugeBuffers.push_back(aBuffer);
|
||||
} else {
|
||||
mClasses[sc].AppendElement(aBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<MLGBuffer>
|
||||
BufferPool::TakeHugeBuffer(size_t aBytes)
|
||||
{
|
||||
static const size_t kMaxSearches = 3;
|
||||
size_t numSearches = std::min(kMaxSearches, mHugeBuffers.size());
|
||||
|
||||
for (size_t i = 0; i < numSearches; i++) {
|
||||
RefPtr<MLGBuffer> buffer = mHugeBuffers.front();
|
||||
mHugeBuffers.pop_front();
|
||||
|
||||
// Don't pick buffers that are massively overallocated.
|
||||
if (buffer->GetSize() >= aBytes && buffer->GetSize() <= aBytes * 2) {
|
||||
return buffer.forget();
|
||||
}
|
||||
|
||||
// Return the buffer to the list.
|
||||
mHugeBuffers.push_back(buffer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */ BufferPool::SizeClass
|
||||
BufferPool::GetSizeClassFromHighBit(size_t aBit)
|
||||
{
|
||||
// If the size is smaller than our smallest size class (which should
|
||||
// never happen), or bigger than our largest size class, we dump it
|
||||
// in the catch-all "huge" list.
|
||||
static const size_t kBitForFirstClass = 4;
|
||||
static const size_t kBitForLastClass = kBitForFirstClass + size_t(SizeClass::Huge);
|
||||
if (aBit < kBitForFirstClass || aBit >= kBitForLastClass) {
|
||||
return SizeClass::Huge;
|
||||
}
|
||||
return SizeClass(aBit - kBitForFirstClass);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
99
gfx/layers/mlgpu/BufferCache.h
Normal file
99
gfx/layers/mlgpu/BufferCache.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_mlgpu_BufferCache_h
|
||||
#define mozilla_gfx_layers_mlgpu_BufferCache_h
|
||||
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include <deque>
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class MLGBuffer;
|
||||
class MLGDevice;
|
||||
|
||||
// This file defines a buffer caching mechanism for systems where constant
|
||||
// buffer offset binding is not allowed. On those systems we must allocate
|
||||
// new buffers each frame, and this cache allows us to re-use them.
|
||||
|
||||
// Track buffers based on their size class, for small buffers.
|
||||
class BufferPool
|
||||
{
|
||||
public:
|
||||
// Remove a buffer from the pool holding at least |aBytes|.
|
||||
RefPtr<MLGBuffer> Take(size_t aBytes);
|
||||
|
||||
// Put a buffer into the pool holding at least |aBytes|.
|
||||
void Put(MLGBuffer* aBuffer);
|
||||
|
||||
BufferPool& operator =(BufferPool&& aOther) {
|
||||
mClasses = Move(aOther.mClasses);
|
||||
mHugeBuffers = Move(aOther.mHugeBuffers);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// Try to see if we can quickly re-use any buffer that didn't fit into a
|
||||
// pre-existing size class.
|
||||
RefPtr<MLGBuffer> TakeHugeBuffer(size_t aBytes);
|
||||
|
||||
enum class SizeClass {
|
||||
One, // 16+ bytes (one constant)
|
||||
Two, // 32+ bytes (two constants)
|
||||
Four, // 64+ bytes (four constants)
|
||||
Eight, // 128+ bytes (eight constants)
|
||||
Medium, // 256+ bytes (16 constants)
|
||||
Large, // 512+ bytes (32 constants)
|
||||
Huge // 1024+ bytes (64+ constants)
|
||||
};
|
||||
static SizeClass GetSizeClassFromHighBit(size_t bit);
|
||||
|
||||
private:
|
||||
typedef nsTArray<RefPtr<MLGBuffer>> BufferList;
|
||||
EnumeratedArray<SizeClass, SizeClass::Huge, BufferList> mClasses;
|
||||
std::deque<RefPtr<MLGBuffer>> mHugeBuffers;
|
||||
};
|
||||
|
||||
// Cache buffer pools based on how long ago they were last used.
|
||||
class BufferCache
|
||||
{
|
||||
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);
|
||||
|
||||
// Rotate buffers after a frame has been completed.
|
||||
void EndFrame();
|
||||
|
||||
private:
|
||||
// Not RefPtr since this would create a cycle.
|
||||
MLGDevice* mDevice;
|
||||
|
||||
// We keep three active buffer pools:
|
||||
// The "expired" pool, which was used two frames ago.
|
||||
// The "previous" pool, which is being used by the previous frame.
|
||||
// The "current" pool, which is being used for the current frame.
|
||||
//
|
||||
// We always allocate from the expired pool into the current pool.
|
||||
// After a frame is completed, the current is moved into the previous,
|
||||
// and the previous is moved into the expired. The expired buffers
|
||||
// are deleted if still alive.
|
||||
//
|
||||
// Since Layers does not allow us to composite more than one frame
|
||||
// ahead, this system ensures the expired buffers are always free.
|
||||
BufferPool mExpired;
|
||||
BufferPool mPrevious;
|
||||
BufferPool mCurrent;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_mlgpu_BufferCache_h
|
105
gfx/layers/mlgpu/CanvasLayerMLGPU.cpp
Normal file
105
gfx/layers/mlgpu/CanvasLayerMLGPU.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "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::SetRegionToRender(LayerIntRegion&& aRegion)
|
||||
{
|
||||
aRegion.AndWith(LayerIntRect::FromUnknownRect(mPictureRect));
|
||||
LayerMLGPU::SetRegionToRender(Move(aRegion));
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
58
gfx/layers/mlgpu/CanvasLayerMLGPU.h
Normal file
58
gfx/layers/mlgpu/CanvasLayerMLGPU.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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 "nsDebug.h" // for NS_RUNTIMEABORT
|
||||
#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:
|
||||
~CanvasLayerMLGPU() override;
|
||||
|
||||
public:
|
||||
void Initialize(const Data& aData) override {
|
||||
MOZ_CRASH("Incompatibe surface type");
|
||||
}
|
||||
|
||||
Layer* GetLayer() override;
|
||||
void Disconnect() override;
|
||||
|
||||
HostLayer* AsHostLayer() override { return this; }
|
||||
CanvasLayerMLGPU* AsCanvasLayerMLGPU() override { return this; }
|
||||
gfx::SamplingFilter GetSamplingFilter() override;
|
||||
void ClearCachedResources() override;
|
||||
void SetRegionToRender(LayerIntRegion&& aRegion) override;
|
||||
|
||||
MOZ_LAYER_DECL_NAME("CanvasLayerMLGPU", TYPE_CANVAS)
|
||||
|
||||
protected:
|
||||
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
void CleanupResources();
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* GFX_CanvasLayerMLGPU_H */
|
103
gfx/layers/mlgpu/ContainerLayerMLGPU.cpp
Normal file
103
gfx/layers/mlgpu/ContainerLayerMLGPU.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ContainerLayerMLGPU.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "MLGDevice.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ContainerLayerMLGPU::ContainerLayerMLGPU(LayerManagerMLGPU* aManager)
|
||||
: ContainerLayer(aManager, nullptr)
|
||||
, LayerMLGPU(aManager)
|
||||
{
|
||||
}
|
||||
|
||||
ContainerLayerMLGPU::~ContainerLayerMLGPU()
|
||||
{
|
||||
while (mFirstChild) {
|
||||
RemoveChild(mFirstChild);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ContainerLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
|
||||
{
|
||||
if (!UseIntermediateSurface()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mTargetOffset = GetIntermediateSurfaceRect().TopLeft().ToUnknownPoint();
|
||||
mTargetSize = GetIntermediateSurfaceRect().Size().ToUnknownSize();
|
||||
|
||||
if (mRenderTarget && mRenderTarget->GetSize() != mTargetSize) {
|
||||
mRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
IntRect viewport(IntPoint(0, 0), mTargetSize);
|
||||
if (!mRenderTarget || !gfxPrefs::AdvancedLayersUseInvalidation()) {
|
||||
// Fine-grained invalidation is disabled, invalidate everything.
|
||||
mInvalidRect = viewport;
|
||||
} else {
|
||||
// Clamp the invalid rect to the viewport.
|
||||
mInvalidRect = mInvalidRect.Intersect(viewport);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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. We can adjust this in the future if needed.
|
||||
IntRect bounds = aRect;
|
||||
bounds.MoveBy(-GetTargetOffset());
|
||||
|
||||
// Note we add the bounds to the invalid rect from the last frame, since we
|
||||
// only clear the area that we actually paint.
|
||||
if (Maybe<IntRect> result = mInvalidRect.SafeUnion(bounds)) {
|
||||
mInvalidRect = result.value();
|
||||
} else {
|
||||
mInvalidRect = IntRect(IntPoint(0, 0), GetTargetSize());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContainerLayerMLGPU::ClearCachedResources()
|
||||
{
|
||||
mRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ContainerLayerMLGPU::IsContentOpaque()
|
||||
{
|
||||
if (GetMixBlendMode() != 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();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
72
gfx/layers/mlgpu/ContainerLayerMLGPU.h
Normal file
72
gfx/layers/mlgpu/ContainerLayerMLGPU.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_mlgpu_ContainerLayerMLGPU_h
|
||||
#define mozilla_gfx_layers_mlgpu_ContainerLayerMLGPU_h
|
||||
|
||||
#include "LayerMLGPU.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ContainerLayerMLGPU final : public ContainerLayer
|
||||
, public LayerMLGPU
|
||||
{
|
||||
public:
|
||||
explicit ContainerLayerMLGPU(LayerManagerMLGPU* aManager);
|
||||
~ContainerLayerMLGPU() override;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
|
||||
|
||||
private:
|
||||
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.
|
||||
gfx::IntRect mInvalidRect;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_mlgpu_ContainerLayerMLGPU_h
|
431
gfx/layers/mlgpu/FrameBuilder.cpp
Normal file
431
gfx/layers/mlgpu/FrameBuilder.cpp
Normal file
@ -0,0 +1,431 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FrameBuilder.h"
|
||||
#include "ContainerLayerMLGPU.h"
|
||||
#include "GeckoProfiler.h" // for profiler_*
|
||||
#include "LayerMLGPU.h"
|
||||
#include "LayerManagerMLGPU.h"
|
||||
#include "MaskOperation.h"
|
||||
#include "RenderPassMLGPU.h"
|
||||
#include "RenderViewMLGPU.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()
|
||||
{
|
||||
}
|
||||
|
||||
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 assign each layer to tiles.
|
||||
{
|
||||
Maybe<Polygon> geometry;
|
||||
RenderTargetIntRect clip(0, 0, target->GetSize().width, target->GetSize().height);
|
||||
|
||||
AssignLayer(mRoot->GetLayer(), mWidgetRenderView, clip, 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<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, Move(aGeometry));
|
||||
}
|
||||
|
||||
bool
|
||||
FrameBuilder::ProcessContainerLayer(ContainerLayer* aContainer,
|
||||
RenderViewMLGPU* aView,
|
||||
const RenderTargetIntRect& aClipRect,
|
||||
Maybe<gfx::Polygon>& aGeometry)
|
||||
{
|
||||
LayerMLGPU* layer = aContainer->AsHostLayer()->AsLayerMLGPU();
|
||||
|
||||
// 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 the container is not part of the invalid region, we don't draw it
|
||||
// or traverse it. Note that we do not pass the geometry here. Otherwise
|
||||
// we could decide the particular split is not visible, and because of the
|
||||
// check above, never bother traversing the container again.
|
||||
IntRect boundingBox = layer->GetClippedBoundingBox(aView, Nothing());
|
||||
const IntRect& invalidRect = aView->GetInvalidRect();
|
||||
if (boundingBox.IsEmpty() || !invalidRect.Intersects(boundingBox)) {
|
||||
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 (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<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<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 = Move(entry.geometry);
|
||||
}
|
||||
|
||||
AssignLayer(child, aView, clip, 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 Matrix4x4& transform = baseLayer->GetEffectiveTransform();
|
||||
|
||||
memcpy(&info->transform, &transform._11, 64);
|
||||
info->clipRect = 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.
|
||||
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, 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());
|
||||
}
|
||||
|
||||
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(
|
||||
§ion,
|
||||
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(
|
||||
§ion,
|
||||
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
|
129
gfx/layers/mlgpu/FrameBuilder.h
Normal file
129
gfx/layers/mlgpu/FrameBuilder.h
Normal file
@ -0,0 +1,129 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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 "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);
|
||||
|
||||
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
|
125
gfx/layers/mlgpu/ImageLayerMLGPU.cpp
Normal file
125
gfx/layers/mlgpu/ImageLayerMLGPU.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "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::SetRegionToRender(LayerIntRegion&& aRegion)
|
||||
{
|
||||
// See bug 1264142.
|
||||
if (mScaleMode == ScaleMode::STRETCH) {
|
||||
aRegion.AndWith(LayerIntRect(0, 0, mScaleToSize.width, mScaleToSize.height));
|
||||
}
|
||||
LayerMLGPU::SetRegionToRender(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
|
54
gfx/layers/mlgpu/ImageLayerMLGPU.h
Normal file
54
gfx/layers/mlgpu/ImageLayerMLGPU.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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 SetRegionToRender(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:
|
||||
~ImageLayerMLGPU() override;
|
||||
|
||||
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
void CleanupResources();
|
||||
|
||||
private:
|
||||
Maybe<gfx::Size> mScale;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
149
gfx/layers/mlgpu/LayerMLGPU.cpp
Normal file
149
gfx/layers/mlgpu/LayerMLGPU.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "LayerManagerMLGPU.h"
|
||||
#include "RenderPassMLGPU.h"
|
||||
#include "RenderViewMLGPU.h"
|
||||
#include "FrameBuilder.h"
|
||||
#include "mozilla/layers/ImageHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
uint64_t LayerMLGPU::sFrameKey = 0;
|
||||
|
||||
LayerMLGPU::LayerMLGPU(LayerManagerMLGPU* aManager)
|
||||
: HostLayer(aManager),
|
||||
mFrameKey(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;
|
||||
|
||||
if (layer->HasMaskLayers()) {
|
||||
mMask = aBuilder->AddMaskOperation(this);
|
||||
} else {
|
||||
mMask = nullptr;
|
||||
}
|
||||
|
||||
if (!OnPrepareToRender(aBuilder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mComputedOpacity = layer->GetEffectiveOpacity();
|
||||
mPrepared = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LayerMLGPU::AssignToView(FrameBuilder* aBuilder,
|
||||
RenderViewMLGPU* aView,
|
||||
Maybe<gfx::Polygon>&& aGeometry)
|
||||
{
|
||||
AddBoundsToView(aBuilder, aView, Move(aGeometry));
|
||||
}
|
||||
|
||||
void
|
||||
LayerMLGPU::AddBoundsToView(FrameBuilder* aBuilder,
|
||||
RenderViewMLGPU* aView,
|
||||
Maybe<gfx::Polygon>&& aGeometry)
|
||||
{
|
||||
IntRect bounds = GetClippedBoundingBox(aView, aGeometry);
|
||||
aView->AddItem(this, bounds, 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::SetRegionToRender(LayerIntRegion&& aRegion)
|
||||
{
|
||||
SetShadowVisibleRegion(Move(aRegion));
|
||||
}
|
||||
|
||||
RefLayerMLGPU::RefLayerMLGPU(LayerManagerMLGPU* aManager)
|
||||
: RefLayer(aManager, static_cast<HostLayer*>(this))
|
||||
, LayerMLGPU(aManager)
|
||||
{
|
||||
}
|
||||
|
||||
RefLayerMLGPU::~RefLayerMLGPU()
|
||||
{
|
||||
}
|
||||
|
||||
ColorLayerMLGPU::ColorLayerMLGPU(LayerManagerMLGPU* aManager)
|
||||
: ColorLayer(aManager, static_cast<HostLayer*>(this))
|
||||
, LayerMLGPU(aManager)
|
||||
{
|
||||
}
|
||||
|
||||
ColorLayerMLGPU::~ColorLayerMLGPU()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
166
gfx/layers/mlgpu/LayerMLGPU.h
Normal file
166
gfx/layers/mlgpu/LayerMLGPU.h
Normal file
@ -0,0 +1,166 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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();
|
||||
|
||||
// This is a wrapper around SetShadowVisibleRegion. 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.
|
||||
virtual void SetRegionToRender(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() {}
|
||||
virtual CompositableHost* GetCompositableHost() override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
LayerMLGPU(LayerManagerMLGPU* aManager);
|
||||
LayerManagerMLGPU* GetManager();
|
||||
|
||||
void AddBoundsToView(FrameBuilder* aBuilder,
|
||||
RenderViewMLGPU* aView,
|
||||
Maybe<gfx::Polygon>&& aGeometry);
|
||||
|
||||
void MarkPrepared();
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class RefLayerMLGPU final : public RefLayer
|
||||
, public LayerMLGPU
|
||||
{
|
||||
public:
|
||||
explicit RefLayerMLGPU(LayerManagerMLGPU* aManager);
|
||||
~RefLayerMLGPU() override;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
MOZ_LAYER_DECL_NAME("RefLayerMLGPU", TYPE_REF)
|
||||
};
|
||||
|
||||
class ColorLayerMLGPU final : public ColorLayer
|
||||
, public LayerMLGPU
|
||||
{
|
||||
public:
|
||||
explicit ColorLayerMLGPU(LayerManagerMLGPU* aManager);
|
||||
~ColorLayerMLGPU() override;
|
||||
|
||||
// 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
|
575
gfx/layers/mlgpu/LayerManagerMLGPU.cpp
Normal file
575
gfx/layers/mlgpu/LayerManagerMLGPU.cpp
Normal file
@ -0,0 +1,575 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "LayerManagerMLGPU.h"
|
||||
#include "LayerTreeInvalidation.h"
|
||||
#include "PaintedLayerMLGPU.h"
|
||||
#include "ImageLayerMLGPU.h"
|
||||
#include "CanvasLayerMLGPU.h"
|
||||
#include "GeckoProfiler.h" // for profiler_*
|
||||
#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 "LayersLogging.h"
|
||||
#include "UtilityMLGPU.h"
|
||||
#include "mozilla/layers/Diagnostics.h"
|
||||
#include "mozilla/layers/TextRenderer.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/widget/WinCompositorWidget.h"
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
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;
|
||||
|
||||
LayerManagerMLGPU::LayerManagerMLGPU(widget::CompositorWidget* aWidget)
|
||||
: mWidget(aWidget),
|
||||
mDrawDiagnostics(false),
|
||||
mUsingInvalidation(false),
|
||||
mCurrentFrame(nullptr)
|
||||
{
|
||||
if (!aWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mDevice) {
|
||||
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();
|
||||
|
||||
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<BorderLayer>
|
||||
LayerManagerMLGPU::CreateBorderLayer()
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("Not yet implemented");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<TextLayer>
|
||||
LayerManagerMLGPU::CreateTextLayer()
|
||||
{
|
||||
MOZ_ASSERT_UNREACHABLE("Not yet implemented");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasLayer>
|
||||
LayerManagerMLGPU::CreateCanvasLayer()
|
||||
{
|
||||
return MakeAndAddRef<CanvasLayerMLGPU>(this);
|
||||
}
|
||||
|
||||
TextureFactoryIdentifier
|
||||
LayerManagerMLGPU::GetTextureFactoryIdentifier()
|
||||
{
|
||||
TextureFactoryIdentifier ident;
|
||||
if (mDevice) {
|
||||
ident = mDevice->GetTextureFactoryIdentifier();
|
||||
}
|
||||
ident.mSupportsBackdropCopyForComponentAlpha = SupportsBackdropCopyForComponentAlpha();
|
||||
return ident;
|
||||
}
|
||||
|
||||
LayersBackend
|
||||
LayerManagerMLGPU::GetBackendType()
|
||||
{
|
||||
return mDevice ? mDevice->GetLayersBackend() : LayersBackend::LAYERS_NONE;
|
||||
}
|
||||
|
||||
bool
|
||||
LayerManagerMLGPU::BeginTransaction()
|
||||
{
|
||||
MOZ_ASSERT(!mTarget);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerMLGPU::BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
|
||||
const gfx::IntRect& aRect)
|
||||
{
|
||||
MOZ_ASSERT(!mTarget);
|
||||
|
||||
mTarget = aTarget;
|
||||
mTargetRect = aRect;
|
||||
return;
|
||||
}
|
||||
|
||||
// Helper class for making sure textures are unlocked.
|
||||
class MOZ_STACK_CLASS AutoUnlockAllTextures
|
||||
{
|
||||
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);
|
||||
|
||||
SetCompositionTime(aTimeStamp);
|
||||
|
||||
TextureSourceProvider::AutoReadUnlockTextures unlock(mTextureSourceProvider);
|
||||
|
||||
if (!mRoot || (aFlags & END_NO_IMMEDIATE_REDRAW) || !mWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCompositionStartTime = TimeStamp::Now();
|
||||
|
||||
IntSize windowSize = mWidget->GetClientSize().ToUnknownSize();
|
||||
if (windowSize.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resize the window if needed.
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
mDrawDiagnostics = gfxPrefs::LayersDrawFPS();
|
||||
mUsingInvalidation = gfxPrefs::AdvancedLayersUseInvalidation();
|
||||
|
||||
// Compute transforms - and the changed area, if enabled.
|
||||
mRoot->ComputeEffectiveTransforms(Matrix4x4());
|
||||
ComputeInvalidRegion();
|
||||
|
||||
// Build and execute draw commands, and present.
|
||||
if (PreRender()) {
|
||||
Composite();
|
||||
PostRender();
|
||||
}
|
||||
|
||||
// Finish composition.
|
||||
mLastCompositionEndTime = TimeStamp::Now();
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerMLGPU::Composite()
|
||||
{
|
||||
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(Move(mInvalidRegion), diagnosticRect)) {
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
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,
|
||||
30,
|
||||
600,
|
||||
TextRenderer::FontType::FixedWidth);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mUsingInvalidation &&
|
||||
(texture->GetSize().width > kDebugOverlayMaxWidth ||
|
||||
texture->GetSize().height > kDebugOverlayMaxHeight))
|
||||
{
|
||||
gfxCriticalNote << "Diagnostic overlay exceeds invalidation area: %s" << Stringify(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) {
|
||||
changed = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr);
|
||||
} 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 = Move(mNextFrameInvalidRegion);
|
||||
mInvalidRegion.OrWith(changed);
|
||||
}
|
||||
|
||||
// Free the old cloned property tree, then clone a new one. Note that we do
|
||||
// this before compositing since our CPU-based occlusion culling will update
|
||||
// the visible region to contain non-occluded draw rects. If a layer will not
|
||||
// be drawn, it will have no visible region. LTI might save this, and if the
|
||||
// layer is removed next frame, LTI will invalidate the wrong area.
|
||||
//
|
||||
// Instead, we always invalidate based on the full shadow tree.
|
||||
//
|
||||
// Note that the old compositor performs CPU-based occlusion culling *before*
|
||||
// invalidation. This maintains consistency, but we have more accurate draw
|
||||
// regions.
|
||||
mClonedLayerTreeProperties = nullptr;
|
||||
mClonedLayerTreeProperties = LayerProperties::CloneFrom(mRoot);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
LayerManagerMLGPU::SupportsBackdropCopyForComponentAlpha()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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 (gfxPrefs::LayersDrawFPS()) {
|
||||
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());
|
||||
mWidgetContext = Nothing();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
136
gfx/layers/mlgpu/LayerManagerMLGPU.h
Normal file
136
gfx/layers/mlgpu/LayerManagerMLGPU.h
Normal file
@ -0,0 +1,136 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_LAYERMANAGERMLGPU_H
|
||||
#define MOZILLA_GFX_LAYERMANAGERMLGPU_H
|
||||
|
||||
#include "Layers.h"
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
#include "LayerMLGPU.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class FrameBuilder;
|
||||
class LayerManagerMLGPU;
|
||||
class RenderPassMLGPU;
|
||||
class SharedBufferMLGPU;
|
||||
class RenderViewMLGPU;
|
||||
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);
|
||||
~LayerManagerMLGPU();
|
||||
|
||||
bool Initialize();
|
||||
void Destroy() override;
|
||||
|
||||
// LayerManager methods
|
||||
bool BeginTransaction() override;
|
||||
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget, const gfx::IntRect& aRect) override;
|
||||
void SetRoot(Layer* aLayer) override { mRoot = aLayer; }
|
||||
already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
|
||||
already_AddRefed<ContainerLayer> CreateContainerLayer() override;
|
||||
already_AddRefed<ImageLayer> CreateImageLayer() override;
|
||||
already_AddRefed<ColorLayer> CreateColorLayer() override;
|
||||
already_AddRefed<TextLayer> CreateTextLayer() override;
|
||||
already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
|
||||
already_AddRefed<RefLayer> CreateRefLayer() override;
|
||||
already_AddRefed<BorderLayer> CreateBorderLayer() override;
|
||||
|
||||
bool AreComponentAlphaLayersEnabled() override;
|
||||
bool BlendingRequiresIntermediateSurface() override;
|
||||
bool SupportsBackdropCopyForComponentAlpha() override;
|
||||
|
||||
// HostLayerManager methods
|
||||
void ForcePresent() override;
|
||||
TextureFactoryIdentifier GetTextureFactoryIdentifier() override;
|
||||
LayersBackend GetBackendType() override;
|
||||
void AddInvalidRegion(const nsIntRegion& aRegion) override;
|
||||
void ClearApproximatelyVisibleRegions(uint64_t aLayersId,
|
||||
const Maybe<uint32_t>& aPresShellId) override {}
|
||||
void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
|
||||
const CSSIntRegion& 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
RefPtr<MLGBuffer> mDiagnosticVertices;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
306
gfx/layers/mlgpu/MLGDevice.cpp
Normal file
306
gfx/layers/mlgpu/MLGDevice.cpp
Normal file
@ -0,0 +1,306 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MLGDevice.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "BufferCache.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "ShaderDefinitionsMLGPU.h"
|
||||
#include "SharedBufferMLGPU.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 = 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),
|
||||
mIsValid(false),
|
||||
mCanUseClearView(false),
|
||||
mCanUseConstantBufferOffsetBinding(false),
|
||||
mMaxConstantBufferBindSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
MLGDevice::~MLGDevice()
|
||||
{
|
||||
}
|
||||
|
||||
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 on enables
|
||||
// Direct3D 11.0/Windows 7/OpenGL-style buffer code paths.
|
||||
if (!gfxPrefs::AdvancedLayersEnableBufferSharing()) {
|
||||
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 (!gfxPrefs::AdvancedLayersEnableClearView()) {
|
||||
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 (gfxPrefs::AdvancedLayersEnableBufferCache()) {
|
||||
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, VertexBufferSection* aSection)
|
||||
{
|
||||
if (!aSection->IsValid()) {
|
||||
return;
|
||||
}
|
||||
SetVertexBuffer(aSlot, aSection->GetBuffer(), aSection->Stride(), aSection->Offset());
|
||||
}
|
||||
|
||||
void
|
||||
MLGDevice::SetPSConstantBuffer(uint32_t aSlot, 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, 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
MLGDevice::Synchronize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
476
gfx/layers/mlgpu/MLGDevice.h
Normal file
476
gfx/layers/mlgpu/MLGDevice.h
Normal file
@ -0,0 +1,476 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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;
|
||||
|
||||
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() {}
|
||||
|
||||
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() {}
|
||||
|
||||
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() {}
|
||||
};
|
||||
|
||||
// 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:
|
||||
~MLGBuffer() override {}
|
||||
};
|
||||
|
||||
// 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,
|
||||
TexturedQuadNV12,
|
||||
TexturedVertexIMC4,
|
||||
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();
|
||||
|
||||
// If Initialize returns false, these may return more useful messages.
|
||||
virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() 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::Color& aColor) = 0;
|
||||
virtual void ClearDepthBuffer(MLGRenderTarget* aRT) = 0;
|
||||
|
||||
// This is only available if CanUseClearView() returns true.
|
||||
virtual void ClearView(
|
||||
MLGRenderTarget* aRT,
|
||||
const gfx::Color& 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, VertexBufferSection* aSection);
|
||||
void SetPSConstantBuffer(uint32_t aSlot, ConstantBufferSection* aSection);
|
||||
void SetVSConstantBuffer(uint32_t aSlot, 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(YUVColorSpace aColorSpace);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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).
|
||||
size_t GetMaxConstantBufferBindSize() const {
|
||||
return mMaxConstantBufferBindSize;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~MLGDevice();
|
||||
|
||||
virtual void SetPrimitiveTopology(MLGPrimitiveTopology aTopology) = 0;
|
||||
|
||||
// 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<YUVColorSpace, YUVColorSpace::UNKNOWN, RefPtr<MLGBuffer>> ColorSpaceArray;
|
||||
ColorSpaceArray mColorSpaceBuffers;
|
||||
|
||||
protected:
|
||||
bool mIsValid;
|
||||
bool mCanUseClearView;
|
||||
bool mCanUseConstantBufferOffsetBinding;
|
||||
size_t mMaxConstantBufferBindSize;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_mlgpu_MLGDevice_h
|
109
gfx/layers/mlgpu/MLGDeviceTypes.h
Normal file
109
gfx/layers/mlgpu/MLGDeviceTypes.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
|
||||
#define mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
|
||||
|
||||
#include "mozilla/TypedEnumBits.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,
|
||||
// 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
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_mlgpu_MLGDeviceTypes_h
|
189
gfx/layers/mlgpu/MaskOperation.cpp
Normal file
189
gfx/layers/mlgpu/MaskOperation.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "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()
|
||||
{
|
||||
}
|
||||
|
||||
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.forget();
|
||||
}
|
||||
|
||||
MaskCombineOperation::MaskCombineOperation(FrameBuilder* aBuilder)
|
||||
: MaskOperation(aBuilder),
|
||||
mBuilder(aBuilder)
|
||||
{
|
||||
}
|
||||
|
||||
MaskCombineOperation::~MaskCombineOperation()
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
mTarget = mBuilder->GetDevice()->CreateRenderTarget(size.Size());
|
||||
mArea = area;
|
||||
mTexture = mTarget->GetTexture();
|
||||
}
|
||||
|
||||
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(§ion, 1, sizeof(texCoords), &texCoords)) {
|
||||
continue;
|
||||
}
|
||||
mInputBuffers.push_back(section);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MaskCombineOperation::Render()
|
||||
{
|
||||
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, Color(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
|
96
gfx/layers/mlgpu/MaskOperation.h
Normal file
96
gfx/layers/mlgpu/MaskOperation.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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);
|
||||
~MaskCombineOperation() override;
|
||||
|
||||
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
|
124
gfx/layers/mlgpu/PaintedLayerMLGPU.cpp
Normal file
124
gfx/layers/mlgpu/PaintedLayerMLGPU.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PaintedLayerMLGPU.h"
|
||||
#include "LayerManagerMLGPU.h"
|
||||
#include "mozilla/layers/LayersHelpers.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)
|
||||
{
|
||||
if (!mHost) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mTexture = mHost->AcquireTextureSource();
|
||||
if (!mTexture) {
|
||||
return false;
|
||||
}
|
||||
mTextureOnWhite = mHost->AcquireTextureSourceOnWhite();
|
||||
|
||||
#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()) {
|
||||
LayerIntRegion visible = Move(GetShadowVisibleRegion());
|
||||
visible = visible.GetBounds();
|
||||
SetShadowVisibleRegion(Move(visible));
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PaintedLayerMLGPU::SetCompositableHost(CompositableHost* aHost)
|
||||
{
|
||||
switch (aHost->GetType()) {
|
||||
case CompositableType::CONTENT_SINGLE:
|
||||
case CompositableType::CONTENT_DOUBLE:
|
||||
mHost = static_cast<ContentHostBase*>(aHost)->AsContentHostTexture();
|
||||
if (!mHost) {
|
||||
gfxWarning() << "ContentHostBase is not a ContentHostTexture";
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CompositableHost*
|
||||
PaintedLayerMLGPU::GetCompositableHost()
|
||||
{
|
||||
return mHost;
|
||||
}
|
||||
|
||||
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
|
83
gfx/layers/mlgpu/PaintedLayerMLGPU.h
Normal file
83
gfx/layers/mlgpu/PaintedLayerMLGPU.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_PAINTEDLAYERMLGPU_H
|
||||
#define MOZILLA_GFX_PAINTEDLAYERMLGPU_H
|
||||
|
||||
#include "LayerManagerMLGPU.h"
|
||||
#include "mozilla/layers/ContentHost.h"
|
||||
#include "nsRegionFwd.h"
|
||||
#include <functional>
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class PaintedLayerMLGPU final
|
||||
: public PaintedLayer,
|
||||
public LayerMLGPU
|
||||
{
|
||||
public:
|
||||
explicit PaintedLayerMLGPU(LayerManagerMLGPU* aManager);
|
||||
~PaintedLayerMLGPU() override;
|
||||
|
||||
// Layer
|
||||
HostLayer* AsHostLayer() override { return this; }
|
||||
PaintedLayerMLGPU* AsPaintedLayerMLGPU() override { return this; }
|
||||
virtual 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;
|
||||
}
|
||||
|
||||
ContentHostTexture* GetContentHost() const {
|
||||
return mHost;
|
||||
}
|
||||
|
||||
nsIntRegion GetRenderRegion() const {
|
||||
nsIntRegion region = GetShadowVisibleRegion().ToUnknownRegion();
|
||||
region.AndWith(gfx::IntRect(region.GetBounds().TopLeft(), mTexture->GetSize()));
|
||||
return region;
|
||||
}
|
||||
|
||||
MOZ_LAYER_DECL_NAME("PaintedLayerMLGPU", TYPE_PAINTED)
|
||||
|
||||
void CleanupCachedResources();
|
||||
|
||||
protected:
|
||||
void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
bool OnPrepareToRender(FrameBuilder* aBuilder) override;
|
||||
void ComputeDrawRegion();
|
||||
|
||||
void CleanupResources();
|
||||
|
||||
private:
|
||||
RefPtr<ContentHostTexture> mHost;
|
||||
RefPtr<TextureSource> mTexture;
|
||||
RefPtr<TextureSource> mTextureOnWhite;
|
||||
gfx::IntRegion mLocalDrawRegion;
|
||||
gfx::IntRegion mTextureRegion;
|
||||
bool mComputedDrawRegion;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
1010
gfx/layers/mlgpu/RenderPassMLGPU.cpp
Normal file
1010
gfx/layers/mlgpu/RenderPassMLGPU.cpp
Normal file
File diff suppressed because it is too large
Load Diff
532
gfx/layers/mlgpu/RenderPassMLGPU.h
Normal file
532
gfx/layers/mlgpu/RenderPassMLGPU.h
Normal file
@ -0,0 +1,532 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_GFX_RENDERPASSMLGPU_H
|
||||
#define MOZILLA_GFX_RENDERPASSMLGPU_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 {
|
||||
explicit 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* GetVertices() {
|
||||
return &mVertices;
|
||||
}
|
||||
VertexStagingBuffer* GetInstances() {
|
||||
return &mInstances;
|
||||
}
|
||||
ConstantStagingBuffer* GetItems() {
|
||||
return &mItems;
|
||||
}
|
||||
|
||||
bool IsCompatible(const ItemInfo& aItem) override;
|
||||
void PrepareForRendering() override;
|
||||
void ExecuteRendering() override;
|
||||
|
||||
virtual 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 buffer bound to "sItems" in shaders. This is used for opaque
|
||||
// batches when the items can be drawn in front-to-back order.
|
||||
bool PrepareItemBuffer();
|
||||
|
||||
// Prepare the vertex buffer, if not using a unit quad. This is used for
|
||||
// opaque batches when the items can be drawn in front-to-back order.
|
||||
bool PrepareVertexBuffer();
|
||||
bool PrepareInstanceBuffer();
|
||||
|
||||
// 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 mVertices;
|
||||
VertexBufferSection mVertexBuffer;
|
||||
|
||||
VertexStagingBuffer mInstances;
|
||||
VertexBufferSection mInstanceBuffer;
|
||||
|
||||
ConstantStagingBuffer mItems;
|
||||
ConstantBufferSection mItemBuffer;
|
||||
|
||||
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 {
|
||||
public:
|
||||
explicit Txn(BatchRenderPass* aPass)
|
||||
: mPass(aPass),
|
||||
mPrevVertexPos(aPass->mVertices.GetPosition()),
|
||||
mPrevItemPos(aPass->mItems.GetPosition()),
|
||||
mPrevInstancePos(aPass->mInstances.GetPosition())
|
||||
{}
|
||||
|
||||
// Add an item based on a draw rect, layer, and optional geometry. The Traits
|
||||
// must contain, at minimum:
|
||||
//
|
||||
// - An "mRect" member as a gfx::Rect, containing the draw rect.
|
||||
// - An "AddInstanceTo" method, which adds instance data for
|
||||
// shaders using unit-quad vertices.
|
||||
// - An "AddVerticesTo" method, which adds triangle list vertices
|
||||
// to a batch's shader data, with optional geometry.
|
||||
// - An "AddItemTo" method, which adds constant buffer data if
|
||||
// needed.
|
||||
//
|
||||
bool Add(const Traits& aTraits, const ItemInfo& aInfo) {
|
||||
// If this succeeds, but we clip the polygon below, that's okay.
|
||||
// Polygons do not use instanced rendering so this won't break
|
||||
// ordering.
|
||||
if (!aTraits.AddItemTo(mPass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPass->mGeometry == GeometryMode::Polygon) {
|
||||
size_t itemIndex = mPass->GetItems()->NumItems() - 1;
|
||||
if (aInfo.geometry) {
|
||||
gfx::Polygon polygon = aInfo.geometry->ClipPolygon(aTraits.mRect);
|
||||
if (polygon.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return aTraits.AddVerticesTo(mPass, aInfo, itemIndex, &polygon);
|
||||
}
|
||||
return aTraits.AddVerticesTo(mPass, aInfo, itemIndex);
|
||||
}
|
||||
return aTraits.AddInstanceTo(mPass, aInfo);
|
||||
}
|
||||
|
||||
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->mVertices.RestorePosition(mPrevVertexPos);
|
||||
mPass->mInstances.RestorePosition(mPrevInstancePos);
|
||||
mPass->mItems.RestorePosition(mPrevItemPos);
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
// 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.
|
||||
bool AddItems(Txn& aTxn,
|
||||
const ItemInfo& aInfo,
|
||||
const nsIntRegion& aDrawRects,
|
||||
const gfx::IntPoint& aDestOrigin,
|
||||
const gfx::IntSize& aTextureSize,
|
||||
const Maybe<gfx::Size>& aScale = Nothing())
|
||||
{
|
||||
gfx::Point origin(aDestOrigin);
|
||||
for (auto iter = aDrawRects.RectIter(); !iter.Done(); iter.Next()) {
|
||||
gfx::Rect drawRect = gfx::Rect(iter.Get());
|
||||
if (!AddItem(aTxn, aInfo, drawRect, origin, aTextureSize, aScale)) {
|
||||
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 ItemInfo& aInfo,
|
||||
const gfx::Rect& aDrawRect,
|
||||
const gfx::Point& aDestOrigin,
|
||||
const gfx::IntSize& aTextureSize,
|
||||
const Maybe<gfx::Size>& aTextureScale = Nothing());
|
||||
|
||||
// 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 ItemInfo& aInfo,
|
||||
const gfx::Rect& aDrawRect,
|
||||
const gfx::Point& aDestOrigin,
|
||||
const gfx::IntSize& aTextureSize,
|
||||
const Maybe<gfx::Size>& aScale);
|
||||
|
||||
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::Color 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;
|
||||
gfx::SamplingFilter mFilter;
|
||||
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:
|
||||
PaintedLayerMLGPU* mAssignedLayer;
|
||||
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;
|
||||
gfx::SamplingFilter mFilter;
|
||||
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;
|
||||
float GetOpacity() const override;
|
||||
bool PrepareBlendState();
|
||||
|
||||
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
|
549
gfx/layers/mlgpu/RenderViewMLGPU.cpp
Normal file
549
gfx/layers/mlgpu/RenderViewMLGPU.cpp
Normal file
@ -0,0 +1,549 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "RenderViewMLGPU.h"
|
||||
#include "ContainerLayerMLGPU.h"
|
||||
#include "FrameBuilder.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "LayersHelpers.h"
|
||||
#include "LayersLogging.h"
|
||||
#include "MLGDevice.h"
|
||||
#include "RenderPassMLGPU.h"
|
||||
#include "ShaderDefinitionsMLGPU.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();
|
||||
|
||||
AL_LOG("RenderView %p root with invalid area %s\n",
|
||||
this,
|
||||
Stringify(mInvalidBounds).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());
|
||||
}
|
||||
|
||||
RenderViewMLGPU::RenderViewMLGPU(FrameBuilder* aBuilder, RenderViewMLGPU* aParent)
|
||||
: mBuilder(aBuilder),
|
||||
mDevice(aBuilder->GetDevice()),
|
||||
mParent(aParent),
|
||||
mContainer(nullptr),
|
||||
mFinishedBuilding(false),
|
||||
mCurrentLayerBufferIndex(kInvalidResourceIndex),
|
||||
mCurrentMaskRectBufferIndex(kInvalidResourceIndex),
|
||||
mNextSortIndex(1),
|
||||
mUseDepthBuffer(gfxPrefs::AdvancedLayersEnableDepthBuffer()),
|
||||
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 tiles front-to-back, depth-first, to minimize render target switching.
|
||||
for (const auto& child : mChildren) {
|
||||
child->Render();
|
||||
}
|
||||
|
||||
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, 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 ||
|
||||
!gfxPrefs::AdvancedLayersEnableCPUOcclusion())
|
||||
{
|
||||
// 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 = Move(aItem.layer->GetShadowVisibleRegion());
|
||||
aItem.layer->SetRegionToRender(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 = Move(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->SetRegionToRender(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->GetShadowVisibleRegion());
|
||||
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.
|
||||
PrepareClear();
|
||||
|
||||
// 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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mDevice->SetRenderTarget(mTarget);
|
||||
mDevice->SetViewport(IntRect(IntPoint(0, 0), mTarget->GetSize()));
|
||||
mDevice->SetScissorRect(Some(mInvalidBounds));
|
||||
|
||||
if (!mWorldConstants.IsValid()) {
|
||||
gfxWarning() << "Failed to allocate constant buffer for world transform";
|
||||
return;
|
||||
}
|
||||
mDevice->SetVSConstantBuffer(kWorldConstantBufferSlot, &mWorldConstants);
|
||||
|
||||
// If using the depth buffer, clear it (if needed) and enable writes.
|
||||
if (mUseDepthBuffer) {
|
||||
if (mDepthBufferNeedsClear) {
|
||||
mDevice->ClearDepthBuffer(mTarget);
|
||||
}
|
||||
mDevice->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.
|
||||
mDevice->SetDepthTestMode(MLGDepthTestMode::ReadOnly);
|
||||
}
|
||||
|
||||
// Clear any pixels that are not occluded, and therefore might require
|
||||
// blending.
|
||||
DrawClear();
|
||||
|
||||
// Render back-to-front passes.
|
||||
for (auto iter = mBackToFront.begin(); iter != mBackToFront.end(); iter++) {
|
||||
ExecutePass(*iter);
|
||||
}
|
||||
|
||||
// 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, §ion);
|
||||
}
|
||||
|
||||
// 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, §ion);
|
||||
}
|
||||
|
||||
// Change the blend state if needed.
|
||||
if (Maybe<MLGBlendState> blendState = aPass->GetBlendState()) {
|
||||
mDevice->SetBlendState(blendState.value());
|
||||
}
|
||||
|
||||
aPass->ExecuteRendering();
|
||||
}
|
||||
|
||||
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::PrepareClear()
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
|
||||
mClearRects.AppendElement(iter.Get().ToUnknownRect());
|
||||
}
|
||||
|
||||
// If ClearView is supported and we're not using a depth buffer, we
|
||||
// can stop here. We'll use the rects as inputs to ClearView.
|
||||
if (mClearRects.IsEmpty() || (mDevice->CanUseClearView() && !mUseDepthBuffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up vertices for a shader-based clear.
|
||||
mDevice->GetSharedVertexBuffer()->Allocate(
|
||||
&mClearInput,
|
||||
mClearRects.Length(),
|
||||
sizeof(IntRect),
|
||||
mClearRects.Elements());
|
||||
mClearRects.Clear();
|
||||
|
||||
// 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.
|
||||
ClearConstants consts(mNextSortIndex++);
|
||||
mDevice->GetSharedVSBuffer()->Allocate(&mClearConstants, consts);
|
||||
}
|
||||
|
||||
void
|
||||
RenderViewMLGPU::DrawClear()
|
||||
{
|
||||
// If we've set up vertices for a shader-based clear, execute that now.
|
||||
if (mClearInput.IsValid()) {
|
||||
mDevice->SetTopology(MLGPrimitiveTopology::UnitQuad);
|
||||
mDevice->SetVertexShader(VertexShaderID::Clear);
|
||||
mDevice->SetVertexBuffer(1, &mClearInput);
|
||||
mDevice->SetVSConstantBuffer(kClearConstantBufferSlot, &mClearConstants);
|
||||
mDevice->SetBlendState(MLGBlendState::Copy);
|
||||
mDevice->SetPixelShader(PixelShaderID::Clear);
|
||||
mDevice->DrawInstanced(4, mClearInput.NumVertices(), 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, if we have a normal rect list, we wanted to use the faster
|
||||
// ClearView.
|
||||
if (!mClearRects.IsEmpty()) {
|
||||
Color color(0.0, 0.0, 0.0, 0.0);
|
||||
mDevice->ClearView(mTarget, color, mClearRects.Elements(), mClearRects.Length());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
135
gfx/layers/mlgpu/RenderViewMLGPU.h
Normal file
135
gfx/layers/mlgpu/RenderViewMLGPU.h
Normal file
@ -0,0 +1,135 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_mlgpu_RenderViewMLGPU_h
|
||||
#define mozilla_gfx_layers_mlgpu_RenderViewMLGPU_h
|
||||
|
||||
#include "LayerManagerMLGPU.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;
|
||||
}
|
||||
|
||||
// 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 PrepareClear();
|
||||
void DrawClear();
|
||||
|
||||
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;
|
||||
|
||||
// If using ClearView-based clears.
|
||||
nsTArray<gfx::IntRect> mClearRects;
|
||||
|
||||
// If using shader-based clears.
|
||||
VertexBufferSection mClearInput;
|
||||
ConstantBufferSection mClearConstants;
|
||||
|
||||
// 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;
|
||||
|
||||
// Depth-buffer tracking.
|
||||
int32_t mNextSortIndex;
|
||||
bool mUseDepthBuffer;
|
||||
bool mDepthBufferNeedsClear;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_mlgpu_RenderViewMLGPU_h
|
55
gfx/layers/mlgpu/ShaderDefinitionsMLGPU-inl.h
Normal file
55
gfx/layers/mlgpu/ShaderDefinitionsMLGPU-inl.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef _include_gfx_layers_mlgpu_ShaderDefinitions_inl_h
|
||||
#define _include_gfx_layers_mlgpu_ShaderDefinitions_inl_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
namespace mlg {
|
||||
|
||||
// This is a helper class for writing vertices for unit-quad based
|
||||
// shaders, since they all share the same input layout.
|
||||
struct SimpleVertex
|
||||
{
|
||||
SimpleVertex(const gfx::Rect& aRect,
|
||||
uint32_t aLayerIndex,
|
||||
int aDepth)
|
||||
: rect(aRect),
|
||||
layerIndex(aLayerIndex),
|
||||
depth(aDepth)
|
||||
{}
|
||||
|
||||
gfx::Rect rect;
|
||||
uint32_t layerIndex;
|
||||
int depth;
|
||||
};
|
||||
|
||||
bool
|
||||
SimpleTraits::AddInstanceTo(ShaderRenderPass* aPass, const ItemInfo& aItem) const
|
||||
{
|
||||
return aPass->GetInstances()->AddItem(SimpleVertex(
|
||||
mRect, aItem.layerIndex, aItem.sortOrder));
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
ColorTraits::AddItemTo(ShaderRenderPass* aPass) const
|
||||
{
|
||||
return aPass->GetItems()->AddItem(mColor);
|
||||
}
|
||||
|
||||
inline bool
|
||||
TexturedTraits::AddItemTo(ShaderRenderPass* aPass) const
|
||||
{
|
||||
return aPass->GetItems()->AddItem(mTexCoords);
|
||||
}
|
||||
|
||||
} // namespace mlg
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _include_gfx_layers_mlgpu_ShaderDefinitions_inl_h
|
127
gfx/layers/mlgpu/ShaderDefinitionsMLGPU.cpp
Normal file
127
gfx/layers/mlgpu/ShaderDefinitionsMLGPU.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ShaderDefinitionsMLGPU.h"
|
||||
#include "RenderPassMLGPU.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
namespace mlg {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
// Helper function for adding triangle vertices to shader buffers.
|
||||
struct TriangleVertex
|
||||
{
|
||||
TriangleVertex(const gfx::Point& aPoint,
|
||||
const ItemInfo& aItem,
|
||||
uint32_t aItemIndex)
|
||||
: point(aPoint),
|
||||
layerIndex(aItem.layerIndex),
|
||||
depth(aItem.sortOrder),
|
||||
itemIndex(aItemIndex)
|
||||
{}
|
||||
|
||||
gfx::Point point;
|
||||
uint32_t layerIndex;
|
||||
int depth;
|
||||
uint32_t itemIndex;
|
||||
};
|
||||
|
||||
bool
|
||||
SimpleTraits::AddVerticesTo(ShaderRenderPass* aPass,
|
||||
const ItemInfo& aItem,
|
||||
uint32_t aItemIndex,
|
||||
const gfx::Polygon* aGeometry) const
|
||||
{
|
||||
VertexStagingBuffer* vertices = aPass->GetVertices();
|
||||
|
||||
// If we don't have geometry, take a fast path where we can hardcode
|
||||
// the set of triangles.
|
||||
if (!aGeometry) {
|
||||
if (!vertices->PrependItem(TriangleVertex(mRect.BottomLeft(), aItem, aItemIndex)) ||
|
||||
!vertices->PrependItem(TriangleVertex(mRect.TopLeft(), aItem, aItemIndex)) ||
|
||||
!vertices->PrependItem(TriangleVertex(mRect.TopRight(), aItem, aItemIndex)) ||
|
||||
!vertices->PrependItem(TriangleVertex(mRect.TopRight(), aItem, aItemIndex)) ||
|
||||
!vertices->PrependItem(TriangleVertex(mRect.BottomRight(), aItem, aItemIndex)) ||
|
||||
!vertices->PrependItem(TriangleVertex(mRect.BottomLeft(), aItem, aItemIndex)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Slow path: full-fledged geometry.
|
||||
nsTArray<Triangle> triangles = aGeometry->ToTriangles();
|
||||
for (const Triangle& t : triangles) {
|
||||
if (!vertices->PrependItem(TriangleVertex(t.p1, aItem, aItemIndex)) ||
|
||||
!vertices->PrependItem(TriangleVertex(t.p2, aItem, aItemIndex)) ||
|
||||
!vertices->PrependItem(TriangleVertex(t.p3, aItem, aItemIndex)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct TexturedTriangleVertex
|
||||
{
|
||||
TexturedTriangleVertex(const gfx::Point& aPoint,
|
||||
const gfx::Point& aTexCoord,
|
||||
const ItemInfo& aItem)
|
||||
: point(aPoint),
|
||||
texCoord(aTexCoord),
|
||||
layerIndex(aItem.layerIndex),
|
||||
depth(aItem.sortOrder)
|
||||
{}
|
||||
|
||||
gfx::Point point;
|
||||
gfx::Point texCoord;
|
||||
uint32_t layerIndex;
|
||||
int depth;
|
||||
};
|
||||
|
||||
bool
|
||||
TexturedTraits::AddVerticesTo(ShaderRenderPass* aPass,
|
||||
const ItemInfo& aItem,
|
||||
uint32_t aItemIndex,
|
||||
const gfx::Polygon* aGeometry) const
|
||||
{
|
||||
VertexStagingBuffer* vertices = aPass->GetVertices();
|
||||
|
||||
using Vertex = TexturedTriangleVertex;
|
||||
|
||||
// If we don't have geometry, take a fast path where we can hardcode
|
||||
// the set of triangles.
|
||||
if (!aGeometry) {
|
||||
if (!vertices->PrependItem(Vertex(mRect.BottomLeft(), mTexCoords.BottomLeft(), aItem)) ||
|
||||
!vertices->PrependItem(Vertex(mRect.TopLeft(), mTexCoords.TopLeft(), aItem)) ||
|
||||
!vertices->PrependItem(Vertex(mRect.TopRight(), mTexCoords.TopRight(), aItem)) ||
|
||||
!vertices->PrependItem(Vertex(mRect.TopRight(), mTexCoords.TopRight(), aItem)) ||
|
||||
!vertices->PrependItem(Vertex(mRect.BottomRight(), mTexCoords.BottomRight(), aItem)) ||
|
||||
!vertices->PrependItem(Vertex(mRect.BottomLeft(), mTexCoords.BottomLeft(), aItem)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Slow path: full-fledged geometry.
|
||||
nsTArray<TexturedTriangle> triangles =
|
||||
GenerateTexturedTriangles(*aGeometry, mRect, mTexCoords);
|
||||
for (const TexturedTriangle& t: triangles) {
|
||||
if (!vertices->PrependItem(Vertex(t.p1, t.textureCoords.p1, aItem)) ||
|
||||
!vertices->PrependItem(Vertex(t.p2, t.textureCoords.p2, aItem)) ||
|
||||
!vertices->PrependItem(Vertex(t.p3, t.textureCoords.p3, aItem)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mlg
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
144
gfx/layers/mlgpu/ShaderDefinitionsMLGPU.h
Normal file
144
gfx/layers/mlgpu/ShaderDefinitionsMLGPU.h
Normal file
@ -0,0 +1,144 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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 kItemBufferSlot = 2;
|
||||
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 = 2;
|
||||
|
||||
// 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;
|
||||
float padding;
|
||||
};
|
||||
|
||||
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 BlendVertexShaderConstants {
|
||||
float backdropTransform[4][4];
|
||||
};
|
||||
|
||||
struct SimpleTraits
|
||||
{
|
||||
explicit SimpleTraits(const gfx::Rect& aRect)
|
||||
: mRect(aRect)
|
||||
{}
|
||||
|
||||
bool AddInstanceTo(ShaderRenderPass* aPass, const ItemInfo& aItem) const;
|
||||
bool AddVerticesTo(ShaderRenderPass* aPass,
|
||||
const ItemInfo& aItem,
|
||||
uint32_t aItemIndex,
|
||||
const gfx::Polygon* aGeometry = nullptr) const;
|
||||
|
||||
gfx::Rect mRect;
|
||||
};
|
||||
|
||||
struct ColorTraits : public SimpleTraits
|
||||
{
|
||||
ColorTraits(const gfx::Rect& aRect, const gfx::Color& aColor)
|
||||
: SimpleTraits(aRect), mColor(aColor)
|
||||
{}
|
||||
|
||||
bool AddItemTo(ShaderRenderPass* aPass) const;
|
||||
|
||||
gfx::Color mColor;
|
||||
};
|
||||
|
||||
struct TexturedTraits : public SimpleTraits
|
||||
{
|
||||
TexturedTraits(const gfx::Rect& aRect, const gfx::Rect& aTexCoords)
|
||||
: SimpleTraits(aRect), mTexCoords(aTexCoords)
|
||||
{}
|
||||
|
||||
bool AddVerticesTo(ShaderRenderPass* aPass,
|
||||
const ItemInfo& aItem,
|
||||
uint32_t aItemIndex,
|
||||
const gfx::Polygon* aGeometry = nullptr) const;
|
||||
bool AddItemTo(ShaderRenderPass* aPass) const;
|
||||
|
||||
gfx::Rect mTexCoords;
|
||||
};
|
||||
|
||||
} // namespace mlg
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
204
gfx/layers/mlgpu/SharedBufferMLGPU.cpp
Normal file
204
gfx/layers/mlgpu/SharedBufferMLGPU.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SharedBufferMLGPU.h"
|
||||
#include "BufferCache.h"
|
||||
#include "MLGDevice.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
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),
|
||||
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;
|
||||
}
|
||||
|
||||
SharedVertexBuffer::SharedVertexBuffer(MLGDevice* aDevice, size_t aDefaultSize)
|
||||
: SharedBufferMLGPU(aDevice, MLGBufferType::Vertex, aDefaultSize)
|
||||
{
|
||||
}
|
||||
|
||||
SharedConstantBuffer::SharedConstantBuffer(MLGDevice* aDevice, size_t aDefaultSize)
|
||||
: SharedBufferMLGPU(aDevice, MLGBufferType::Constant, aDefaultSize)
|
||||
{
|
||||
mMaxConstantBufferBindSize = aDevice->GetMaxConstantBufferBindSize();
|
||||
mCanUseOffsetAllocation = aDevice->CanUseConstantBufferOffsetBinding();
|
||||
}
|
||||
|
||||
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
|
372
gfx/layers/mlgpu/SharedBufferMLGPU.h
Normal file
372
gfx/layers/mlgpu/SharedBufferMLGPU.h
Normal file
@ -0,0 +1,372 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_mlgpu_SharedBufferMLGPU_h
|
||||
#define mozilla_gfx_layers_mlgpu_SharedBufferMLGPU_h
|
||||
|
||||
#include "ShaderDefinitionsMLGPU.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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
: mOffset(-1),
|
||||
mNumVertices(0),
|
||||
mStride(0)
|
||||
{}
|
||||
|
||||
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) {
|
||||
mBuffer = aBuffer;
|
||||
mOffset = aOffset;
|
||||
mNumVertices = aNumVertices;
|
||||
mStride = aStride;
|
||||
}
|
||||
|
||||
protected:
|
||||
RefPtr<MLGBuffer> mBuffer;
|
||||
ptrdiff_t mOffset;
|
||||
size_t mNumVertices;
|
||||
size_t mStride;
|
||||
};
|
||||
|
||||
class ConstantBufferSection final
|
||||
{
|
||||
friend class SharedConstantBuffer;
|
||||
|
||||
public:
|
||||
ConstantBufferSection()
|
||||
: mOffset(-1)
|
||||
{}
|
||||
|
||||
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) {
|
||||
mBuffer = aBuffer;
|
||||
mOffset = aOffset;
|
||||
mNumBytes = aBytes;
|
||||
mNumItems = 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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() : mPtr(nullptr) {}
|
||||
~AutoBufferUploadBase() {
|
||||
if (mBuffer) {
|
||||
UnmapBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void Init(void* aPtr) {
|
||||
MOZ_ASSERT(!mPtr && aPtr);
|
||||
mPtr = aPtr;
|
||||
}
|
||||
void Init(void* aPtr, MLGDevice* aDevice, MLGBuffer* aBuffer) {
|
||||
MOZ_ASSERT(!mPtr && aPtr);
|
||||
mPtr = aPtr;
|
||||
mDevice = aDevice;
|
||||
mBuffer = 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()
|
||||
{}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
19
gfx/layers/mlgpu/StagingBuffer.cpp
Normal file
19
gfx/layers/mlgpu/StagingBuffer.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "StagingBuffer.h"
|
||||
#include "MLGDevice.h"
|
||||
#include "ShaderDefinitionsMLGPU.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ConstantStagingBuffer::ConstantStagingBuffer(MLGDevice* aDevice)
|
||||
: StagingBuffer(mlg::kMaxConstantBufferSize)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
251
gfx/layers/mlgpu/StagingBuffer.h
Normal file
251
gfx/layers/mlgpu/StagingBuffer.h
Normal file
@ -0,0 +1,251 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_gfx_layers_mlgpu_StagingBuffer_h
|
||||
#define mozilla_gfx_layers_mlgpu_StagingBuffer_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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 = 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
|
105
gfx/layers/mlgpu/TextureSourceProviderMLGPU.cpp
Normal file
105
gfx/layers/mlgpu/TextureSourceProviderMLGPU.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "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()
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureSourceProviderMLGPU::NotifyNotUsedAfterComposition(TextureHost* aTextureHost)
|
||||
{
|
||||
if (!mDevice) {
|
||||
return false;
|
||||
}
|
||||
return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
56
gfx/layers/mlgpu/TextureSourceProviderMLGPU.h
Normal file
56
gfx/layers/mlgpu/TextureSourceProviderMLGPU.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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);
|
||||
~TextureSourceProviderMLGPU() override;
|
||||
|
||||
already_AddRefed<DataTextureSource>
|
||||
CreateDataTextureSource(TextureFlags aFlags) override;
|
||||
|
||||
already_AddRefed<DataTextureSource>
|
||||
CreateDataTextureSourceAround(gfx::DataSourceSurface* aSurface) 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
|
||||
virtual 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
|
210
gfx/layers/mlgpu/TexturedLayerMLGPU.cpp
Normal file
210
gfx/layers/mlgpu/TexturedLayerMLGPU.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "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, 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, 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)
|
||||
{
|
||||
}
|
||||
|
||||
TempImageLayerMLGPU::~TempImageLayerMLGPU()
|
||||
{
|
||||
}
|
||||
|
||||
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
|
105
gfx/layers/mlgpu/TexturedLayerMLGPU.h
Normal file
105
gfx/layers/mlgpu/TexturedLayerMLGPU.h
Normal file
@ -0,0 +1,105 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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() override;
|
||||
|
||||
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:
|
||||
~TempImageLayerMLGPU() override;
|
||||
|
||||
private:
|
||||
gfx::SamplingFilter mFilter;
|
||||
bool mIsOpaque;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_mlgpu_TexturedLayerMLGPU_h
|
39
gfx/layers/mlgpu/UtilityMLGPU.h
Normal file
39
gfx/layers/mlgpu/UtilityMLGPU.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#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__)
|
||||
#else
|
||||
# define AL_LOG(...)
|
||||
#endif
|
||||
|
||||
#endif // mozilla_gfx_layers_mlgpu_UtilityMLGPU_h
|
@ -66,12 +66,14 @@ 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 += [
|
||||
@ -148,6 +150,7 @@ EXPORTS.mozilla.layers += [
|
||||
'composite/ImageLayerComposite.h',
|
||||
'composite/LayerManagerComposite.h',
|
||||
'composite/PaintedLayerComposite.h',
|
||||
'composite/TextRenderer.h',
|
||||
'composite/TextureHost.h',
|
||||
'composite/TiledContentHost.h',
|
||||
'Compositor.h',
|
||||
@ -195,6 +198,12 @@ EXPORTS.mozilla.layers += [
|
||||
'LayerMetricsWrapper.h',
|
||||
'LayersHelpers.h',
|
||||
'LayersTypes.h',
|
||||
'mlgpu/LayerManagerMLGPU.h',
|
||||
'mlgpu/LayerMLGPU.h',
|
||||
'mlgpu/MLGDevice.h',
|
||||
'mlgpu/MLGDeviceTypes.h',
|
||||
'mlgpu/ShaderDefinitionsMLGPU.h',
|
||||
'mlgpu/UtilityMLGPU.h',
|
||||
'opengl/CompositingRenderTargetOGL.h',
|
||||
'opengl/CompositorOGL.h',
|
||||
'opengl/MacIOSurfaceTextureClientOGL.h',
|
||||
@ -394,6 +403,23 @@ UNIFIED_SOURCES += [
|
||||
'LayersLogging.cpp',
|
||||
'LayerSorter.cpp',
|
||||
'LayersTypes.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/MLGDevice.cpp',
|
||||
'mlgpu/PaintedLayerMLGPU.cpp',
|
||||
'mlgpu/RenderPassMLGPU.cpp',
|
||||
'mlgpu/RenderViewMLGPU.cpp',
|
||||
'mlgpu/ShaderDefinitionsMLGPU.cpp',
|
||||
'mlgpu/SharedBufferMLGPU.cpp',
|
||||
'mlgpu/StagingBuffer.cpp',
|
||||
'mlgpu/TexturedLayerMLGPU.cpp',
|
||||
'mlgpu/TextureSourceProviderMLGPU.cpp',
|
||||
'opengl/CompositingRenderTargetOGL.cpp',
|
||||
'opengl/CompositorOGL.cpp',
|
||||
'opengl/GLBlitTextureImageHelper.cpp',
|
||||
@ -481,11 +507,15 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
GENERATED_FILES = [
|
||||
'CompositorD3D11Shaders.h',
|
||||
'MLGShaders.h',
|
||||
]
|
||||
|
||||
d3d11_shaders = GENERATED_FILES['CompositorD3D11Shaders.h']
|
||||
d3d11_shaders.script = 'd3d11/genshaders.py'
|
||||
d3d11_shaders.inputs = ['d3d11/shaders.manifest']
|
||||
mlg_shaders = GENERATED_FILES['MLGShaders.h']
|
||||
mlg_shaders.script = 'd3d11/genshaders.py'
|
||||
mlg_shaders.inputs = ['d3d11/mlgshaders/shaders.manifest']
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/docshell/base', # for nsDocShell.h
|
||||
|
@ -561,6 +561,13 @@ private:
|
||||
DECL_GFX_PREF(Live, "layers.low-precision-opacity", LowPrecisionOpacity, float, 1.0f);
|
||||
DECL_GFX_PREF(Live, "layers.low-precision-resolution", LowPrecisionResolution, float, 0.25f);
|
||||
DECL_GFX_PREF(Live, "layers.max-active", MaxActiveLayers, int32_t, -1);
|
||||
DECL_GFX_PREF(Once, "layers.mlgpu.dev-enabled", AdvancedLayersEnabledDoNotUseDirectly, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.mlgpu.enable-buffer-cache", AdvancedLayersEnableBufferCache, bool, true);
|
||||
DECL_GFX_PREF(Once, "layers.mlgpu.enable-buffer-sharing", AdvancedLayersEnableBufferSharing, bool, true);
|
||||
DECL_GFX_PREF(Once, "layers.mlgpu.enable-clear-view", AdvancedLayersEnableClearView, bool, true);
|
||||
DECL_GFX_PREF(Once, "layers.mlgpu.enable-cpu-occlusion", AdvancedLayersEnableCPUOcclusion, bool, true);
|
||||
DECL_GFX_PREF(Once, "layers.mlgpu.enable-depth-buffer", AdvancedLayersEnableDepthBuffer, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.mlgpu.enable-invalidation", AdvancedLayersUseInvalidation, bool, true);
|
||||
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
|
||||
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
|
||||
|
@ -83,6 +83,14 @@ public:
|
||||
return mArray[size_t(aIndex)];
|
||||
}
|
||||
|
||||
EnumeratedArray& operator =(EnumeratedArray&& aOther)
|
||||
{
|
||||
for (size_t i = 0; i < kSize; i++) {
|
||||
mArray[i] = Move(aOther.mArray[i]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef typename ArrayType::iterator iterator;
|
||||
typedef typename ArrayType::const_iterator const_iterator;
|
||||
typedef typename ArrayType::reverse_iterator reverse_iterator;
|
||||
|
@ -5716,6 +5716,14 @@ pref("dom.payments.request.enabled", false);
|
||||
pref("fuzzing.enabled", false);
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
pref("layers.mlgpu.dev-enabled", false);
|
||||
|
||||
// Both this and the master "enabled" pref must be on to use Advanced LAyers
|
||||
// on Windows 7.
|
||||
pref("layers.mlgpu.enable-on-windows7", false);
|
||||
#endif
|
||||
|
||||
// Set advanced layers preferences here to have them show up in about:config or
|
||||
// to be overridable in reftest.list files. They should pretty much all be set
|
||||
// to a value of 2, and the conditional-pref code in gfxPrefs.h will convert
|
||||
|
Loading…
Reference in New Issue
Block a user