gecko-dev/gfx/layers/mlgpu/RenderPassMLGPU.h

487 строки
14 KiB
C++

/* -*- 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* GetInstances() {
return &mInstances;
}
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 mask/opacity buffer bound in most pixel shaders.
bool SetupPSBuffer0(float aOpacity);
bool HasMask() const {
return !!mMask;
}
MaskOperation* GetMask() const {
return mMask;
}
protected:
GeometryMode mGeometry;
RefPtr<MaskOperation> mMask;
bool mHasRectTransformAndClip;
VertexStagingBuffer mInstances;
VertexBufferSection mInstanceBuffer;
ConstantBufferSection mPSBuffer0;
};
// This contains various helper functions for building vertices and shader
// inputs for layers.
template <typename Traits>
class BatchRenderPass : public ShaderRenderPass
{
public:
BatchRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem)
: ShaderRenderPass(aBuilder, aItem)
{}
protected:
// It is tricky to determine ahead of time whether or not we'll have enough
// room in our buffers to hold all draw commands for a layer, especially
// since layers can have multiple draw rects. We don't want to draw one rect,
// reject the item, then redraw the same rect again in another batch.
// To deal with this we use a transaction approach and reject the transaction
// if we couldn't add everything.
class Txn {
public:
explicit Txn(BatchRenderPass* aPass)
: mPass(aPass),
mPrevInstancePos(aPass->mInstances.GetPosition())
{}
bool Add(const Traits& aTraits) {
if (!AddImpl(aTraits)) {
return Fail();
}
return true;
}
// Add an item based on a draw rect, layer, and optional geometry. This is
// defined in RenderPassMLGPU-inl.h, since it needs access to
// ShaderDefinitionsMLGPU-inl.h.
bool AddImpl(const Traits& aTraits);
bool Fail() {
MOZ_ASSERT(!mStatus.isSome() || !mStatus.value());
mStatus = Some(false);
return false;
}
bool Commit() {
MOZ_ASSERT(!mStatus.isSome() || !mStatus.value());
if (mStatus.isSome()) {
return false;
}
mStatus = Some(true);
return true;
}
~Txn() {
if (!mStatus.isSome() || !mStatus.value()) {
mPass->mInstances.RestorePosition(mPrevInstancePos);
}
}
private:
BatchRenderPass* mPass;
VertexStagingBuffer::Position mPrevVertexPos;
VertexStagingBuffer::Position mPrevItemPos;
ConstantStagingBuffer::Position mPrevInstancePos;
Maybe<bool> mStatus;
};
};
// Shaders which sample from a texture should inherit from this.
class TexturedRenderPass : public BatchRenderPass<TexturedTraits>
{
public:
explicit TexturedRenderPass(FrameBuilder* aBuilder, const ItemInfo& aItem);
protected:
// 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