forked from mirrors/gecko-dev
Backed out changeset 8069471cda21 (bug 1365879)
This commit is contained in:
parent
1f871b61e4
commit
4119f2f8fb
76 changed files with 3 additions and 11768 deletions
|
|
@ -1,313 +0,0 @@
|
||||||
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,7 +10,6 @@
|
||||||
#include "mozilla/gfx/Rect.h"
|
#include "mozilla/gfx/Rect.h"
|
||||||
#include "mozilla/gfx/Matrix.h"
|
#include "mozilla/gfx/Matrix.h"
|
||||||
#include "mozilla/gfx/Polygon.h"
|
#include "mozilla/gfx/Polygon.h"
|
||||||
#include "nsRegion.h"
|
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include "mozilla/dom/TabChild.h"
|
#include "mozilla/dom/TabChild.h"
|
||||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||||
#include "mozilla/layers/APZChild.h"
|
#include "mozilla/layers/APZChild.h"
|
||||||
#include "nsIContentInlines.h"
|
|
||||||
|
|
||||||
#include "InputData.h" // for InputData
|
#include "InputData.h" // for InputData
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,6 @@ class TextRenderer;
|
||||||
class CompositingRenderTarget;
|
class CompositingRenderTarget;
|
||||||
struct FPSState;
|
struct FPSState;
|
||||||
class PaintCounter;
|
class PaintCounter;
|
||||||
class LayerMLGPU;
|
|
||||||
class LayerManagerMLGPU;
|
|
||||||
class UiCompositorControllerParent;
|
class UiCompositorControllerParent;
|
||||||
|
|
||||||
static const int kVisualWarningDuration = 150; // ms
|
static const int kVisualWarningDuration = 150; // ms
|
||||||
|
|
@ -125,9 +123,6 @@ public:
|
||||||
virtual HostLayerManager* AsHostLayerManager() override {
|
virtual HostLayerManager* AsHostLayerManager() override {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
virtual LayerManagerMLGPU* AsLayerManagerMLGPU() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
|
void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
|
||||||
{
|
{
|
||||||
|
|
@ -555,8 +550,6 @@ public:
|
||||||
|
|
||||||
virtual Layer* GetLayer() = 0;
|
virtual Layer* GetLayer() = 0;
|
||||||
|
|
||||||
virtual LayerMLGPU* AsLayerMLGPU() { return nullptr; }
|
|
||||||
|
|
||||||
virtual bool SetCompositableHost(CompositableHost*)
|
virtual bool SetCompositableHost(CompositableHost*)
|
||||||
{
|
{
|
||||||
// We must handle this gracefully, see bug 967824
|
// We must handle this gracefully, see bug 967824
|
||||||
|
|
@ -576,10 +569,6 @@ public:
|
||||||
{
|
{
|
||||||
mShadowVisibleRegion = aRegion;
|
mShadowVisibleRegion = aRegion;
|
||||||
}
|
}
|
||||||
void SetShadowVisibleRegion(LayerIntRegion&& aRegion)
|
|
||||||
{
|
|
||||||
mShadowVisibleRegion = Move(aRegion);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetShadowOpacity(float aOpacity)
|
void SetShadowOpacity(float aOpacity)
|
||||||
{
|
{
|
||||||
|
|
@ -607,12 +596,11 @@ public:
|
||||||
// These getters can be used anytime.
|
// These getters can be used anytime.
|
||||||
float GetShadowOpacity() { return mShadowOpacity; }
|
float GetShadowOpacity() { return mShadowOpacity; }
|
||||||
const Maybe<ParentLayerIntRect>& GetShadowClipRect() { return mShadowClipRect; }
|
const Maybe<ParentLayerIntRect>& GetShadowClipRect() { return mShadowClipRect; }
|
||||||
const LayerIntRegion& GetShadowVisibleRegion() const { return mShadowVisibleRegion; }
|
const LayerIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
|
||||||
const gfx::Matrix4x4& GetShadowBaseTransform() { return mShadowTransform; }
|
const gfx::Matrix4x4& GetShadowBaseTransform() { return mShadowTransform; }
|
||||||
gfx::Matrix4x4 GetShadowTransform();
|
gfx::Matrix4x4 GetShadowTransform();
|
||||||
bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
|
bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
|
||||||
bool GetShadowOpacitySetByAnimation() { return mShadowOpacitySetByAnimation; }
|
bool GetShadowOpacitySetByAnimation() { return mShadowOpacitySetByAnimation; }
|
||||||
LayerIntRegion&& GetShadowVisibleRegion() { return Move(mShadowVisibleRegion); }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HostLayerManager* mCompositorManager;
|
HostLayerManager* mCompositorManager;
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ using namespace gfx;
|
||||||
|
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
bool CanUsePartialPresents(ID3D11Device* aDevice);
|
static bool CanUsePartialPresents(ID3D11Device* aDevice);
|
||||||
|
|
||||||
const FLOAT sBlendFactor[] = { 0, 0, 0, 0 };
|
const FLOAT sBlendFactor[] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
|
@ -255,7 +255,7 @@ CompositorD3D11::Initialize(nsCString* const out_failureReason)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
CanUsePartialPresents(ID3D11Device* aDevice)
|
CanUsePartialPresents(ID3D11Device* aDevice)
|
||||||
{
|
{
|
||||||
if (gfxPrefs::PartialPresent() > 0) {
|
if (gfxPrefs::PartialPresent() > 0) {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,330 +0,0 @@
|
||||||
/* -*- 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,14 +90,6 @@ SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes)
|
|
||||||
{
|
|
||||||
aTexture->SetPrivateDataInterface(
|
|
||||||
sD3D11TextureUsage,
|
|
||||||
new TextureMemoryMeasurer(aBytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize)
|
GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -483,7 +483,6 @@ inline uint32_t GetMaxTextureSizeForFeatureLevel(D3D_FEATURE_LEVEL aFeatureLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetMaxTextureSizeFromDevice(ID3D11Device* aDevice);
|
uint32_t GetMaxTextureSizeFromDevice(ID3D11Device* aDevice);
|
||||||
void ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes);
|
|
||||||
|
|
||||||
class AutoLockD3D11Texture
|
class AutoLockD3D11Texture
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
};
|
|
||||||
|
|
@ -1,540 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
/* -*- 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"
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
};
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
};
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
};
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
};
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
- 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
|
|
||||||
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
};
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
/* -*- 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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
/* -*- 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
/* -*- 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 */
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,431 +0,0 @@
|
||||||
/* -*- 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()
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("FrameBuilder", "Build", js::ProfileEntry::Category::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()
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("FrameBuilder", "Render", js::ProfileEntry::Category::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
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,579 +0,0 @@
|
||||||
/* -*- 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)
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("LayerManager", "EndTransaction",
|
|
||||||
js::ProfileEntry::Category::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()
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("LayerManagerMLGPU", "Composite",
|
|
||||||
js::ProfileEntry::Category::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()
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("LayerManagerMLGPU", "RenderLayers",
|
|
||||||
js::ProfileEntry::Category::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()
|
|
||||||
{
|
|
||||||
PROFILER_LABEL("LayerManagerMLGPU", "PreRender",
|
|
||||||
js::ProfileEntry::Category::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
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,306 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,476 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,189 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,532 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,550 +0,0 @@
|
||||||
/* -*- 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();
|
|
||||||
mActualBounds = Some(IntRect());
|
|
||||||
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
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
/* -*- 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 actual bounds of the view as computed by summing the visible bounds of
|
|
||||||
// child layers. We use this to right-size the intermediate surface. If unset,
|
|
||||||
// we do not right-size the intermediate surface.
|
|
||||||
Maybe<gfx::IntRect> mActualBounds;
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,372 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
/* -*- 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
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
/* -*- 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,14 +66,12 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||||
'd3d11/DeviceAttachmentsD3D11.h',
|
'd3d11/DeviceAttachmentsD3D11.h',
|
||||||
'd3d11/DiagnosticsD3D11.h',
|
'd3d11/DiagnosticsD3D11.h',
|
||||||
'd3d11/HelpersD3D11.h',
|
'd3d11/HelpersD3D11.h',
|
||||||
'd3d11/MLGDeviceD3D11.h',
|
|
||||||
'd3d11/ReadbackManagerD3D11.h',
|
'd3d11/ReadbackManagerD3D11.h',
|
||||||
'd3d11/ShaderDefinitionsD3D11.h',
|
'd3d11/ShaderDefinitionsD3D11.h',
|
||||||
'd3d11/TextureD3D11.h',
|
'd3d11/TextureD3D11.h',
|
||||||
]
|
]
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'd3d11/DiagnosticsD3D11.cpp',
|
'd3d11/DiagnosticsD3D11.cpp',
|
||||||
'd3d11/MLGDeviceD3D11.cpp',
|
|
||||||
'd3d11/TextureD3D11.cpp',
|
'd3d11/TextureD3D11.cpp',
|
||||||
]
|
]
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
|
|
@ -150,7 +148,6 @@ EXPORTS.mozilla.layers += [
|
||||||
'composite/ImageLayerComposite.h',
|
'composite/ImageLayerComposite.h',
|
||||||
'composite/LayerManagerComposite.h',
|
'composite/LayerManagerComposite.h',
|
||||||
'composite/PaintedLayerComposite.h',
|
'composite/PaintedLayerComposite.h',
|
||||||
'composite/TextRenderer.h',
|
|
||||||
'composite/TextureHost.h',
|
'composite/TextureHost.h',
|
||||||
'composite/TiledContentHost.h',
|
'composite/TiledContentHost.h',
|
||||||
'Compositor.h',
|
'Compositor.h',
|
||||||
|
|
@ -198,12 +195,6 @@ EXPORTS.mozilla.layers += [
|
||||||
'LayerMetricsWrapper.h',
|
'LayerMetricsWrapper.h',
|
||||||
'LayersHelpers.h',
|
'LayersHelpers.h',
|
||||||
'LayersTypes.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/CompositingRenderTargetOGL.h',
|
||||||
'opengl/CompositorOGL.h',
|
'opengl/CompositorOGL.h',
|
||||||
'opengl/MacIOSurfaceTextureClientOGL.h',
|
'opengl/MacIOSurfaceTextureClientOGL.h',
|
||||||
|
|
@ -403,23 +394,6 @@ UNIFIED_SOURCES += [
|
||||||
'LayersLogging.cpp',
|
'LayersLogging.cpp',
|
||||||
'LayerSorter.cpp',
|
'LayerSorter.cpp',
|
||||||
'LayersTypes.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/CompositingRenderTargetOGL.cpp',
|
||||||
'opengl/CompositorOGL.cpp',
|
'opengl/CompositorOGL.cpp',
|
||||||
'opengl/GLBlitTextureImageHelper.cpp',
|
'opengl/GLBlitTextureImageHelper.cpp',
|
||||||
|
|
@ -507,15 +481,11 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||||
GENERATED_FILES = [
|
GENERATED_FILES = [
|
||||||
'CompositorD3D11Shaders.h',
|
'CompositorD3D11Shaders.h',
|
||||||
'MLGShaders.h',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
d3d11_shaders = GENERATED_FILES['CompositorD3D11Shaders.h']
|
d3d11_shaders = GENERATED_FILES['CompositorD3D11Shaders.h']
|
||||||
d3d11_shaders.script = 'd3d11/genshaders.py'
|
d3d11_shaders.script = 'd3d11/genshaders.py'
|
||||||
d3d11_shaders.inputs = ['d3d11/shaders.manifest']
|
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 += [
|
LOCAL_INCLUDES += [
|
||||||
'/docshell/base', # for nsDocShell.h
|
'/docshell/base', # for nsDocShell.h
|
||||||
|
|
|
||||||
|
|
@ -560,13 +560,6 @@ private:
|
||||||
DECL_GFX_PREF(Live, "layers.low-precision-opacity", LowPrecisionOpacity, float, 1.0f);
|
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.low-precision-resolution", LowPrecisionResolution, float, 0.25f);
|
||||||
DECL_GFX_PREF(Live, "layers.max-active", MaxActiveLayers, int32_t, -1);
|
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(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.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
|
||||||
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
|
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
|
||||||
|
|
|
||||||
|
|
@ -83,14 +83,6 @@ public:
|
||||||
return mArray[size_t(aIndex)];
|
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::iterator iterator;
|
||||||
typedef typename ArrayType::const_iterator const_iterator;
|
typedef typename ArrayType::const_iterator const_iterator;
|
||||||
typedef typename ArrayType::reverse_iterator reverse_iterator;
|
typedef typename ArrayType::reverse_iterator reverse_iterator;
|
||||||
|
|
|
||||||
|
|
@ -5716,14 +5716,6 @@ pref("dom.payments.request.enabled", false);
|
||||||
pref("fuzzing.enabled", false);
|
pref("fuzzing.enabled", false);
|
||||||
#endif
|
#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
|
// 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 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
|
// to a value of 2, and the conditional-pref code in gfxPrefs.h will convert
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue