mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1042291 - Implement a better heuristic for when to use HW accelerated <canvas> r=snorp
This commit is contained in:
parent
4d3fe6fe9f
commit
677c5c8d14
@ -724,6 +724,9 @@ public:
|
||||
static_cast<CanvasRenderingContext2DUserData*>(aData);
|
||||
if (self->mContext) {
|
||||
self->mContext->MarkContextClean();
|
||||
if (self->mContext->mDrawObserver) {
|
||||
self->mContext->mDrawObserver->FrameEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
bool IsForContext(CanvasRenderingContext2D *aContext)
|
||||
@ -826,6 +829,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
|
||||
, mResetLayer(true)
|
||||
, mIPC(false)
|
||||
, mStream(nullptr)
|
||||
, mDrawObserver(nullptr)
|
||||
, mIsEntireFrameInvalid(false)
|
||||
, mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
|
||||
, mInvalidateCount(0)
|
||||
@ -838,6 +842,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D()
|
||||
mRenderingMode = RenderingMode::SoftwareBackendMode;
|
||||
}
|
||||
|
||||
mDrawObserver = new CanvasDrawObserver(this);
|
||||
}
|
||||
|
||||
CanvasRenderingContext2D::~CanvasRenderingContext2D()
|
||||
@ -3816,6 +3821,10 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
||||
uint8_t optional_argc,
|
||||
ErrorResult& error)
|
||||
{
|
||||
if (mDrawObserver) {
|
||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6);
|
||||
|
||||
RefPtr<SourceSurface> srcSurf;
|
||||
@ -4332,6 +4341,10 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx,
|
||||
double aSy, double aSw,
|
||||
double aSh, ErrorResult& error)
|
||||
{
|
||||
if (mDrawObserver) {
|
||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
|
||||
}
|
||||
|
||||
EnsureTarget();
|
||||
if (!IsTargetValid()) {
|
||||
error.Throw(NS_ERROR_FAILURE);
|
||||
@ -4412,6 +4425,10 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
uint32_t aHeight,
|
||||
JSObject** aRetval)
|
||||
{
|
||||
if (mDrawObserver) {
|
||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::GetImageData);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aWidth && aHeight);
|
||||
|
||||
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
|
||||
@ -4585,6 +4602,10 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w
|
||||
bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
|
||||
int32_t dirtyWidth, int32_t dirtyHeight)
|
||||
{
|
||||
if (mDrawObserver) {
|
||||
mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::PutImageData);
|
||||
}
|
||||
|
||||
if (w == 0 || h == 0) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "mozilla/dom/CanvasPattern.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "imgIEncoder.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
@ -115,6 +116,7 @@ private:
|
||||
|
||||
struct CanvasBidiProcessor;
|
||||
class CanvasRenderingContext2DUserData;
|
||||
class CanvasDrawObserver;
|
||||
|
||||
/**
|
||||
** CanvasRenderingContext2D
|
||||
@ -767,6 +769,11 @@ protected:
|
||||
|
||||
RefPtr<gl::SurfaceStream> mStream;
|
||||
|
||||
// This observes our draw calls at the beginning of the canvas
|
||||
// lifetime and switches to software or GPU mode depending on
|
||||
// what it thinks is best
|
||||
CanvasDrawObserver *mDrawObserver;
|
||||
|
||||
/**
|
||||
* Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
|
||||
* Redraw is called, reset to false when Render is called.
|
||||
@ -1081,6 +1088,73 @@ protected:
|
||||
}
|
||||
|
||||
friend struct CanvasBidiProcessor;
|
||||
friend class CanvasDrawObserver;
|
||||
};
|
||||
|
||||
class CanvasDrawObserver
|
||||
{
|
||||
public:
|
||||
CanvasDrawObserver(CanvasRenderingContext2D* aCanvasContext)
|
||||
: mCanvasContext(aCanvasContext)
|
||||
, mDisabled(false)
|
||||
, mSoftwarePreferredCalls(0)
|
||||
, mGPUPreferredCalls(0)
|
||||
, mFramesRendered(0)
|
||||
, mCreationTime(TimeStamp::NowLoRes())
|
||||
{}
|
||||
|
||||
// Only enumerate draw calls that could affect the heuristic
|
||||
enum DrawCallType {
|
||||
PutImageData,
|
||||
GetImageData,
|
||||
DrawImage
|
||||
};
|
||||
|
||||
void DidDrawCall(DrawCallType aType) {
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aType) {
|
||||
case PutImageData:
|
||||
case GetImageData:
|
||||
mSoftwarePreferredCalls++;
|
||||
break;
|
||||
case DrawImage:
|
||||
mGPUPreferredCalls++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FrameEnd() {
|
||||
if (mDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFramesRendered++;
|
||||
|
||||
TimeDuration timeElapsed = TimeStamp::NowLoRes() - mCreationTime;
|
||||
|
||||
// We log the first 30 frames of any canvas object then make a
|
||||
// call to determine whether it should be GPU or CPU backed
|
||||
if (mFramesRendered >= 30 || timeElapsed.ToSeconds() >= 5.0) {
|
||||
if (mGPUPreferredCalls >= mSoftwarePreferredCalls) {
|
||||
mCanvasContext->SwitchRenderingMode(CanvasRenderingContext2D::RenderingMode::OpenGLBackendMode);
|
||||
} else {
|
||||
mCanvasContext->SwitchRenderingMode(CanvasRenderingContext2D::RenderingMode::SoftwareBackendMode);
|
||||
}
|
||||
|
||||
mDisabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CanvasRenderingContext2D* mCanvasContext;
|
||||
bool mDisabled;
|
||||
unsigned int mSoftwarePreferredCalls;
|
||||
unsigned int mGPUPreferredCalls;
|
||||
unsigned int mFramesRendered;
|
||||
TimeStamp mCreationTime;
|
||||
};
|
||||
|
||||
MOZ_FINISH_NESTED_ENUM_CLASS(CanvasRenderingContext2D::CanvasMultiGetterType)
|
||||
|
Loading…
Reference in New Issue
Block a user