Bug 1349799 - Implement WebGLPowerPreference and gl::CreateContextFlags::HIGH_POWER. - r=kvark

Based on patches by :daoshengmu.

MozReview-Commit-ID: FSbJV8DLyJ4
This commit is contained in:
Jeff Gilbert 2018-06-22 16:47:02 -07:00
parent 45170d1834
commit 3cdbe9fdb9
4 changed files with 72 additions and 81 deletions

View File

@ -94,19 +94,27 @@ using namespace mozilla::gl;
using namespace mozilla::layers;
WebGLContextOptions::WebGLContextOptions()
: alpha(true)
, depth(true)
, stencil(false)
, premultipliedAlpha(true)
, antialias(true)
, preserveDrawingBuffer(false)
, failIfMajorPerformanceCaveat(false)
{
// Set default alpha state based on preference.
if (gfxPrefs::WebGLDefaultNoAlpha())
alpha = false;
}
bool
WebGLContextOptions::operator==(const WebGLContextOptions& r) const
{
bool eq = true;
eq &= (alpha == r.alpha);
eq &= (depth == r.depth);
eq &= (stencil == r.stencil);
eq &= (premultipliedAlpha == r.premultipliedAlpha);
eq &= (antialias == r.antialias);
eq &= (preserveDrawingBuffer == r.preserveDrawingBuffer);
eq &= (failIfMajorPerformanceCaveat == r.failIfMajorPerformanceCaveat);
eq &= (powerPreference == r.powerPreference);
return eq;
}
WebGLContext::WebGLContext()
: WebGLContextUnchecked(nullptr)
, mMaxPerfWarnings(gfxPrefs::WebGLMaxPerfWarnings())
@ -368,6 +376,7 @@ WebGLContext::SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options,
newOpts.antialias = attributes.mAntialias;
newOpts.preserveDrawingBuffer = attributes.mPreserveDrawingBuffer;
newOpts.failIfMajorPerformanceCaveat = attributes.mFailIfMajorPerformanceCaveat;
newOpts.powerPreference = attributes.mPowerPreference;
if (attributes.mAlpha.WasPassed())
newOpts.alpha = attributes.mAlpha.Value();
@ -386,7 +395,7 @@ WebGLContext::SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options,
newOpts.preserveDrawingBuffer ? 1 : 0);
#endif
if (mOptionsFrozen && newOpts != mOptions) {
if (mOptionsFrozen && !(newOpts == mOptions)) {
// Error if the options are already frozen, and the ones that were asked for
// aren't the same as what they were originally.
return NS_ERROR_FAILURE;
@ -667,6 +676,22 @@ WebGLContext::CreateAndInitGL(bool forceEnabled,
flags |= gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE;
}
switch (mOptions.powerPreference) {
case dom::WebGLPowerPreference::Low_power:
break;
// Eventually add a heuristic, but for now default to high-performance.
// We can even make it dynamic by holding on to a ForceDiscreteGPUHelperCGL iff
// we decide it's a high-performance application:
// - Non-trivial canvas size
// - Many draw calls
// - Same origin with root page (try to stem bleeding from WebGL ads/trackers)
case dom::WebGLPowerPreference::High_performance:
default:
flags |= gl::CreateContextFlags::HIGH_POWER;
break;
}
#ifdef XP_MACOSX
const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
nsString vendorID, deviceID;
@ -1410,6 +1435,7 @@ WebGLContext::GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& r
result.mPremultipliedAlpha = mOptions.premultipliedAlpha;
result.mPreserveDrawingBuffer = mOptions.preserveDrawingBuffer;
result.mFailIfMajorPerformanceCaveat = mOptions.failIfMajorPerformanceCaveat;
result.mPowerPreference = mOptions.powerPreference;
}
void

View File

@ -30,10 +30,6 @@
#include "ScopedGLHelpers.h"
#include "TexUnpackBlob.h"
#ifdef XP_MACOSX
#include "ForceDiscreteGPUHelperCGL.h"
#endif
// Local
#include "CacheMap.h"
#include "WebGLContextLossHandler.h"
@ -117,30 +113,17 @@ void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
struct WebGLContextOptions
{
// these are defaults
bool alpha = true;
bool depth = true;
bool stencil = false;
bool premultipliedAlpha = true;
bool antialias = true;
bool preserveDrawingBuffer = false;
bool failIfMajorPerformanceCaveat = false;
dom::WebGLPowerPreference powerPreference = dom::WebGLPowerPreference::Default;
WebGLContextOptions();
bool operator==(const WebGLContextOptions& other) const {
return
alpha == other.alpha &&
depth == other.depth &&
stencil == other.stencil &&
premultipliedAlpha == other.premultipliedAlpha &&
antialias == other.antialias &&
preserveDrawingBuffer == other.preserveDrawingBuffer;
}
bool operator!=(const WebGLContextOptions& other) const {
return !operator==(other);
}
bool alpha;
bool depth;
bool stencil;
bool premultipliedAlpha;
bool antialias;
bool preserveDrawingBuffer;
bool failIfMajorPerformanceCaveat;
bool operator==(const WebGLContextOptions&) const;
};
// From WebGLContextUtils
@ -2041,16 +2024,6 @@ public:
template <typename WebGLObjectType>
JSObject* WebGLObjectAsJSObject(JSContext* cx, const WebGLObjectType*,
ErrorResult& rv) const;
#ifdef XP_MACOSX
// see bug 713305. This RAII helper guarantees that we're on the discrete GPU, during its lifetime
// Debouncing note: we don't want to switch GPUs too frequently, so try to not create and destroy
// these objects at high frequency. Having WebGLContext's hold one such object seems fine,
// because WebGLContext objects only go away during GC, which shouldn't happen too frequently.
// If in the future GC becomes much more frequent, we may have to revisit then (maybe use a timer).
ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
#endif
public:
// console logging helpers
void GenerateWarning(const char* fmt, ...) const MOZ_FORMAT_PRINTF(2, 3);

View File

@ -206,26 +206,6 @@ static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered_accel_webrende
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_allow_offline[] = {
NSOpenGLPFAAllowOfflineRenderers,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_accel[] = {
NSOpenGLPFAAccelerated,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_coreProfile[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
0
};
static NSOpenGLContext*
CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs)
{
@ -307,23 +287,33 @@ CreateOffscreenFBOContext(CreateContextFlags flags)
NSOpenGLContext* context = nullptr;
if (!(flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
context = CreateWithFormat(kAttribs_offscreen_coreProfile);
}
if (!context) {
if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER) {
if (gfxPrefs::RequireHardwareGL())
context = CreateWithFormat(kAttribs_singleBuffered);
else
context = CreateWithFormat(kAttribs_offscreen_allow_offline);
std::vector<NSOpenGLPixelFormatAttribute> attribs;
} else {
if (gfxPrefs::RequireHardwareGL())
context = CreateWithFormat(kAttribs_offscreen_accel);
else
context = CreateWithFormat(kAttribs_offscreen);
}
if (flags & CreateContextFlags::ALLOW_OFFLINE_RENDERER ||
!(flags & CreateContextFlags::HIGH_POWER))
{
// This is really poorly named on Apple's part, but "AllowOfflineRenderers" means
// that we want to allow running on the iGPU instead of requiring the dGPU.
attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
}
if (gfxPrefs::RequireHardwareGL()) {
attribs.push_back(NSOpenGLPFAAccelerated);
}
if (!(flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE)) {
auto coreAttribs = attribs;
coreAttribs.push_back(NSOpenGLPFAOpenGLProfile);
coreAttribs.push_back(NSOpenGLProfileVersion3_2Core);
coreAttribs.push_back(0);
context = CreateWithFormat(coreAttribs.data());
}
if (!context) {
attribs.push_back(0);
context = CreateWithFormat(attribs.data());
}
if (!context) {
NS_WARNING("Failed to create NSOpenGLContext.");
return nullptr;

View File

@ -45,7 +45,7 @@ struct GLFormats
GLsizei samples;
};
enum class CreateContextFlags : int8_t {
enum class CreateContextFlags : uint8_t {
NONE = 0,
REQUIRE_COMPAT_PROFILE = 1 << 0,
// Force the use of hardware backed GL, don't allow software implementations.
@ -57,6 +57,8 @@ enum class CreateContextFlags : int8_t {
NO_VALIDATION = 1 << 4,
PREFER_ROBUSTNESS = 1 << 5,
HIGH_POWER = 1 << 6,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)