Bug 1124394 - Support Core profiles for GLContext. - r=kamidphish

This commit is contained in:
Jeff Gilbert 2015-02-12 19:00:41 -08:00
parent d4d465b6d0
commit ea33309bb2
30 changed files with 448 additions and 349 deletions

View File

@ -505,7 +505,7 @@ IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
static already_AddRefed<GLContext>
CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
bool requireCompatProfile, WebGLContext* webgl)
{
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
@ -515,7 +515,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
return nullptr;
}
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless();
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile);
if (!gl) {
webgl->GenerateWarning("Error during native OpenGL init.");
return nullptr;
@ -530,7 +530,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
// Eventually, we want to be able to pick ANGLE-EGL or native EGL.
static already_AddRefed<GLContext>
CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
bool requireCompatProfile, WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
@ -543,7 +543,7 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
return nullptr;
}
gl = gl::GLContextProviderEGL::CreateHeadless();
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile);
if (!gl) {
webgl->GenerateWarning("Error during ANGLE OpenGL init.");
return nullptr;
@ -555,13 +555,13 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
}
static already_AddRefed<GLContext>
CreateHeadlessEGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
CreateHeadlessEGL(bool forceEnabled, bool requireCompatProfile,
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
#ifdef ANDROID
gl = gl::GLContextProviderEGL::CreateHeadless();
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile);
if (!gl) {
webgl->GenerateWarning("Error during EGL OpenGL init.");
return nullptr;
@ -583,16 +583,22 @@ CreateHeadlessGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"))
disableANGLE = true;
bool requireCompatProfile = webgl->IsWebGL2() ? false : true;
nsRefPtr<GLContext> gl;
if (preferEGL)
gl = CreateHeadlessEGL(forceEnabled, gfxInfo, webgl);
gl = CreateHeadlessEGL(forceEnabled, requireCompatProfile, webgl);
if (!gl && !disableANGLE)
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, webgl);
if (!gl && !disableANGLE) {
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, requireCompatProfile,
webgl);
}
if (!gl)
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, webgl);
if (!gl) {
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo,
requireCompatProfile, webgl);
}
return gl.forget();
}

View File

@ -1209,9 +1209,10 @@ protected:
// -------------------------------------------------------------------------
// WebGL 2 specifics (implemented in WebGL2Context.cpp)
public:
virtual bool IsWebGL2() const = 0;
protected:
bool InitWebGL2();
// -------------------------------------------------------------------------

View File

@ -2106,7 +2106,6 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
// if we're reading alpha, we may need to do fixup. Note that we don't allow
// GL_ALPHA to readpixels currently, but we had the code written for it already.
const bool formatHasAlpha = format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_RGBA;
if (!formatHasAlpha)

View File

@ -1117,11 +1117,12 @@ WebGLContext::AssertCachedState()
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);
GLint stencilBits = 0;
gl->fGetIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
const GLuint stencilRefMask = (1 << stencilBits) - 1;
if (GetStencilBits(&stencilBits)) {
const GLuint stencilRefMask = (1 << stencilBits) - 1;
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
}
// GLES 3.0.4, $4.1.4, p177:
// [...] the front and back stencil mask are both set to the value `2^s - 1`, where

View File

@ -1779,8 +1779,8 @@ WebGLContext::InitAndValidateGL()
MakeContextCurrent();
// on desktop OpenGL, we always keep vertex attrib 0 array enabled
if (!gl->IsGLES())
// For OpenGL compat. profiles, we always keep vertex attrib 0 array enabled.
if (gl->IsCompatibilityProfile())
gl->fEnableVertexAttribArray(0);
if (MinCapabilityMode())
@ -1889,7 +1889,7 @@ WebGLContext::InitAndValidateGL()
// Always 1 for GLES2
mMaxFramebufferColorAttachments = 1;
if (!gl->IsGLES()) {
if (gl->IsCompatibilityProfile()) {
// gl_PointSize is always available in ES2 GLSL, but has to be
// specifically enabled on desktop GLSL.
gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);

View File

@ -182,7 +182,7 @@ protected:
return true;
}
mGLContext = GLContextProvider::CreateHeadless();
mGLContext = GLContextProvider::CreateHeadless(false);
return mGLContext;
}

View File

@ -91,9 +91,8 @@ static nsRefPtr<GLContext> sPluginContext = nullptr;
static bool EnsureGLContext()
{
if (!sPluginContext) {
gfxIntSize dummySize(16, 16);
sPluginContext = GLContextProvider::CreateOffscreen(dummySize,
SurfaceCaps::Any());
bool requireCompatProfile = true;
sPluginContext = GLContextProvider::CreateHeadless(requireCompatProfile);
}
return sPluginContext != nullptr;

View File

@ -8,6 +8,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <vector>
#include "GLContext.h"
#include "GLBlitHelper.h"
@ -156,8 +157,7 @@ static const char *sExtensionNames[] = {
"GL_OES_texture_half_float",
"GL_OES_texture_half_float_linear",
"GL_OES_texture_npot",
"GL_OES_vertex_array_object",
nullptr
"GL_OES_vertex_array_object"
};
static bool
@ -501,6 +501,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
MakeCurrent();
if (mInitialized) {
MOZ_ASSERT(mProfile != ContextProfile::Unknown);
uint32_t version = 0;
ParseGLVersion(this, &version);
@ -656,6 +658,15 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) {
SymLoadStruct moreSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetStringi, { "GetStringi", nullptr } },
END_SYMBOLS
};
MOZ_ALWAYS_TRUE(LoadSymbols(moreSymbols, trygl, prefix));
}
InitExtensions();
InitFeatures();
@ -670,12 +681,6 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
MarkUnsupported(GLFeature::standard_derivatives);
}
if (Vendor() == GLVendor::Imagination &&
Renderer() == GLRenderer::SGX540) {
// Bug 980048
MarkExtensionUnsupported(OES_EGL_sync);
}
if (Renderer() == GLRenderer::MicrosoftBasicRenderDriver) {
// Bug 978966: on Microsoft's "Basic Render Driver" (software renderer)
// multisampling hardcodes blending with the default blendfunc, which breaks WebGL.
@ -1468,10 +1473,13 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
// We're ready for final setup.
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
if (mCaps.any)
DetermineCaps();
// TODO: Remove SurfaceCaps::any.
if (mCaps.any) {
mCaps.any = false;
mCaps.color = true;
mCaps.alpha = false;
}
UpdatePixelFormat();
UpdateGLFormats(mCaps);
mTexGarbageBin = new TextureGarbageBin(this);
@ -1593,61 +1601,105 @@ GLContext::DebugCallback(GLenum source,
void
GLContext::InitExtensions()
{
MakeCurrent();
const char* extensions = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
if (!extensions)
return;
MOZ_ASSERT(IsCurrent());
InitializeExtensionsBitSet(mAvailableExtensions, extensions,
sExtensionNames);
std::vector<nsCString> driverExtensionList;
if (WorkAroundDriverBugs() &&
Vendor() == GLVendor::Qualcomm) {
if (IsFeatureProvidedByCoreSymbols(GLFeature::get_string_indexed)) {
GLuint count = 0;
GetUIntegerv(LOCAL_GL_NUM_EXTENSIONS, &count);
for (GLuint i = 0; i < count; i++) {
// This is UTF-8.
const char* rawExt = (const char*)fGetStringi(LOCAL_GL_EXTENSIONS, i);
// Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it.
MarkExtensionSupported(OES_EGL_sync);
// We CANNOT use nsDependentCString here, because the spec doesn't guarantee
// that the pointers returned are different, only that their contents are.
// On Flame, each of these index string queries returns the same address.
driverExtensionList.push_back(nsCString(rawExt));
}
} else {
MOZ_ALWAYS_TRUE(!fGetError());
const char* rawExts = (const char*)fGetString(LOCAL_GL_EXTENSIONS);
MOZ_ALWAYS_TRUE(!fGetError());
if (rawExts) {
nsDependentCString exts(rawExts);
SplitByChar(exts, ' ', &driverExtensionList);
}
}
if (WorkAroundDriverBugs() &&
Renderer() == GLRenderer::AndroidEmulator) {
// the Android emulator, which we use to run B2G reftests on,
// doesn't expose the OES_rgb8_rgba8 extension, but it seems to
// support it (tautologically, as it only runs on desktop GL).
MarkExtensionSupported(OES_rgb8_rgba8);
const bool shouldDumpExts = ShouldDumpExts();
if (shouldDumpExts) {
printf_stderr("%i GL driver extensions: (*: recognized)\n",
(uint32_t)driverExtensionList.size());
}
if (WorkAroundDriverBugs() &&
Vendor() == GLVendor::VMware &&
Renderer() == GLRenderer::GalliumLlvmpipe)
{
// The llvmpipe driver that is used on linux try servers appears to have
// buggy support for s3tc/dxt1 compressed textures.
// See Bug 975824.
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
MarkExtensionUnsupported(EXT_texture_compression_dxt1);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt3);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt5);
}
MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sExtensionNames,
&mAvailableExtensions);
if (WorkAroundDriverBugs()) {
if (Vendor() == GLVendor::Qualcomm) {
// Some Adreno drivers do not report GL_OES_EGL_sync, but they really do support it.
MarkExtensionSupported(OES_EGL_sync);
}
if (Vendor() == GLVendor::Imagination &&
Renderer() == GLRenderer::SGX540)
{
// Bug 980048
MarkExtensionUnsupported(OES_EGL_sync);
}
if (Renderer() == GLRenderer::AndroidEmulator) {
// the Android emulator, which we use to run B2G reftests on,
// doesn't expose the OES_rgb8_rgba8 extension, but it seems to
// support it (tautologically, as it only runs on desktop GL).
MarkExtensionSupported(OES_rgb8_rgba8);
}
if (Vendor() == GLVendor::VMware &&
Renderer() == GLRenderer::GalliumLlvmpipe)
{
// The llvmpipe driver that is used on linux try servers appears to have
// buggy support for s3tc/dxt1 compressed textures.
// See Bug 975824.
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
MarkExtensionUnsupported(EXT_texture_compression_dxt1);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt3);
MarkExtensionUnsupported(ANGLE_texture_compression_dxt5);
}
#ifdef XP_MACOSX
// Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD
// 3000 appears to be buggy WRT updating sub-images of S3TC
// textures with glCompressedTexSubImage2D. Works on Intel HD 4000
// and Intel HD 5000/Iris that I tested.
if (WorkAroundDriverBugs() &&
nsCocoaFeatures::OSXVersionMajor() == 10 &&
nsCocoaFeatures::OSXVersionMinor() == 9 &&
Renderer() == GLRenderer::IntelHD3000)
{
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
}
// Bug 1009642: On OSX Mavericks (10.9), the driver for Intel HD
// 3000 appears to be buggy WRT updating sub-images of S3TC
// textures with glCompressedTexSubImage2D. Works on Intel HD 4000
// and Intel HD 5000/Iris that I tested.
if (nsCocoaFeatures::OSXVersionMajor() == 10 &&
nsCocoaFeatures::OSXVersionMinor() == 9 &&
Renderer() == GLRenderer::IntelHD3000)
{
MarkExtensionUnsupported(EXT_texture_compression_s3tc);
}
#endif
}
if (shouldDumpExts) {
printf_stderr("\nActivated extensions:\n");
for (size_t i = 0; i < mAvailableExtensions.size(); i++) {
if (!mAvailableExtensions[i])
continue;
const char* ext = sExtensionNames[i];
printf_stderr("[%i] %s\n", (uint32_t)i, ext);
}
}
}
void
GLContext::PlatformStartup()
{
RegisterStrongMemoryReporter(new GfxTexturesReporter());
RegisterStrongMemoryReporter(new GfxTexturesReporter());
}
// Common code for checking for both GL extensions and GLX extensions.
@ -1688,66 +1740,6 @@ GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
return false;
}
void
GLContext::DetermineCaps()
{
PixelBufferFormat format = QueryPixelFormat();
SurfaceCaps caps;
caps.color = !!format.red && !!format.green && !!format.blue;
caps.bpp16 = caps.color && format.ColorBits() == 16;
caps.alpha = !!format.alpha;
caps.depth = !!format.depth;
caps.stencil = !!format.stencil;
caps.antialias = format.samples > 1;
caps.preserve = true;
mCaps = caps;
}
PixelBufferFormat
GLContext::QueryPixelFormat()
{
PixelBufferFormat format;
ScopedBindFramebuffer autoFB(this, 0);
fGetIntegerv(LOCAL_GL_RED_BITS , &format.red );
fGetIntegerv(LOCAL_GL_GREEN_BITS, &format.green);
fGetIntegerv(LOCAL_GL_BLUE_BITS , &format.blue );
fGetIntegerv(LOCAL_GL_ALPHA_BITS, &format.alpha);
fGetIntegerv(LOCAL_GL_DEPTH_BITS, &format.depth);
fGetIntegerv(LOCAL_GL_STENCIL_BITS, &format.stencil);
fGetIntegerv(LOCAL_GL_SAMPLES, &format.samples);
return format;
}
void
GLContext::UpdatePixelFormat()
{
PixelBufferFormat format = QueryPixelFormat();
#ifdef MOZ_GL_DEBUG
const SurfaceCaps& caps = Caps();
MOZ_ASSERT(!caps.any, "Did you forget to DetermineCaps()?");
MOZ_ASSERT(caps.color == !!format.red);
MOZ_ASSERT(caps.color == !!format.green);
MOZ_ASSERT(caps.color == !!format.blue);
// These we either must have if they're requested, or
// we can have if they're not.
MOZ_ASSERT(caps.alpha == !!format.alpha || !caps.alpha);
MOZ_ASSERT(caps.depth == !!format.depth || !caps.depth);
MOZ_ASSERT(caps.stencil == !!format.stencil || !caps.stencil);
MOZ_ASSERT(caps.antialias == (format.samples > 1));
#endif
mPixelFormat = new PixelBufferFormat(format);
}
GLFormats
GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
{
@ -2417,6 +2409,13 @@ GLContext::FlushIfHeavyGLCallsSinceLastFlush()
fFlush();
}
/*static*/ bool
GLContext::ShouldDumpExts()
{
static bool ret = PR_GetEnv("MOZ_GL_DUMP_EXTS");
return ret;
}
bool
DoesStringMatch(const char* aString, const char *aWantedString)
{
@ -2444,8 +2443,96 @@ DoesStringMatch(const char* aString, const char *aWantedString)
/*static*/ bool
GLContext::ShouldSpew()
{
static bool spew = PR_GetEnv("MOZ_GL_SPEW");
return spew;
static bool ret = PR_GetEnv("MOZ_GL_SPEW");
return ret;
}
void
SplitByChar(const nsACString& str, const char delim, std::vector<nsCString>* const out)
{
uint32_t start = 0;
while (true) {
int32_t end = str.FindChar(' ', start);
if (end == -1)
break;
uint32_t len = (uint32_t)end - start;
nsDependentCSubstring substr(str, start, len);
out->push_back(nsCString(substr));
start = end + 1;
continue;
}
nsDependentCSubstring substr(str, start);
out->push_back(nsCString(substr));
}
void
GLContext::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
{
MOZ_ASSERT(src && dest);
MOZ_ASSERT(dest->GetSize() == src->mSize);
MOZ_ASSERT(dest->GetFormat() == (src->mHasAlpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8));
MakeCurrent();
SharedSurface* prev = GetLockedSurface();
const bool needsSwap = src != prev;
if (needsSwap) {
if (prev)
prev->UnlockProd();
src->LockProd();
}
GLuint tempFB = 0;
{
ScopedBindFramebuffer autoFB(this);
// Even though we're reading. We're doing it on
// the producer side. So we call ProducerAcquire
// instead of ConsumerAcquire.
src->ProducerAcquire();
if (src->mAttachType == AttachmentType::Screen) {
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
} else {
fGenFramebuffers(1, &tempFB);
fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, tempFB);
switch (src->mAttachType) {
case AttachmentType::GLTexture:
fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
src->ProdTextureTarget(), src->ProdTexture(), 0);
break;
case AttachmentType::GLRenderbuffer:
fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, src->ProdRenderbuffer());
break;
default:
MOZ_CRASH("bad `src->mAttachType`.");
}
DebugOnly<GLenum> status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
}
ReadPixelsIntoDataSurface(this, dest);
src->ProducerRelease();
}
if (tempFB)
fDeleteFramebuffers(1, &tempFB);
if (needsSwap) {
src->UnlockProd();
if (prev)
prev->LockProd();
}
}
} /* namespace gl */

View File

@ -104,6 +104,7 @@ enum class GLFeature {
get_integer_indexed,
get_integer64_indexed,
get_query_object_iv,
get_string_indexed,
gpu_shader4,
instanced_arrays,
instanced_non_arrays,
@ -308,7 +309,6 @@ public:
virtual bool IsCurrent() = 0;
protected:
bool mInitialized;
bool mIsOffscreen;
bool mIsGlobalSharedContext;
@ -325,9 +325,12 @@ protected:
GLVendor mVendor;
GLRenderer mRenderer;
inline void SetProfileVersion(ContextProfile profile, unsigned int version) {
MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before initialization!");
MOZ_ASSERT(profile != ContextProfile::Unknown && profile != ContextProfile::OpenGL, "Invalid `profile` for SetProfileVersion");
void SetProfileVersion(ContextProfile profile, uint32_t version) {
MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before"
" initialization!");
MOZ_ASSERT(profile != ContextProfile::Unknown &&
profile != ContextProfile::OpenGL,
"Invalid `profile` for SetProfileVersion");
MOZ_ASSERT(version >= 100, "Invalid `version` for SetProfileVersion");
mVersion = version;
@ -457,6 +460,7 @@ public:
return mAvailableExtensions[aKnownExtension];
}
protected:
void MarkExtensionUnsupported(GLExtensions aKnownExtension) {
mAvailableExtensions[aKnownExtension] = 0;
}
@ -465,42 +469,6 @@ public:
mAvailableExtensions[aKnownExtension] = 1;
}
public:
template<size_t N>
static void InitializeExtensionsBitSet(std::bitset<N>& extensionsBitset,
const char* extStr,
const char** extList)
{
char* exts = ::strdup(extStr);
if (ShouldSpew())
printf_stderr("Extensions: %s\n", exts);
char* cur = exts;
bool done = false;
while (!done) {
char* space = strchr(cur, ' ');
if (space) {
*space = '\0';
} else {
done = true;
}
for (int i = 0; extList[i]; ++i) {
if (PL_strcasecmp(cur, extList[i]) == 0) {
if (ShouldSpew())
printf_stderr("Found extension %s\n", cur);
extensionsBitset[i] = true;
}
}
cur = space + 1;
}
free(exts);
}
protected:
std::bitset<Extensions_Max> mAvailableExtensions;
// -----------------------------------------------------------------------------
@ -2022,6 +1990,8 @@ public:
}
private:
friend class SharedSurface;
void raw_fBindFramebuffer(GLenum target, GLuint framebuffer) {
BEFORE_GL_CALL;
mSymbols.fBindFramebuffer(target, framebuffer);
@ -3180,6 +3150,17 @@ public:
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// get_string_indexed
const GLubyte* fGetStringi(GLenum name, GLuint index) {
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fGetStringi);
const GLubyte* ret = mSymbols.fGetStringi(name, index);
AFTER_GL_CALL;
return ret;
}
// -----------------------------------------------------------------------------
// Constructor
protected:
@ -3448,11 +3429,9 @@ public:
fViewport(0, 0, size.width, size.height);
mCaps = mScreen->mCaps;
if (mCaps.any)
DetermineCaps();
MOZ_ASSERT(!mCaps.any);
UpdateGLFormats(mCaps);
UpdatePixelFormat();
return true;
}
@ -3475,10 +3454,8 @@ public:
protected:
SurfaceCaps mCaps;
nsAutoPtr<GLFormats> mGLFormats;
nsAutoPtr<PixelBufferFormat> mPixelFormat;
public:
void DetermineCaps();
const SurfaceCaps& Caps() const {
return mCaps;
}
@ -3494,14 +3471,6 @@ public:
return *mGLFormats;
}
PixelBufferFormat QueryPixelFormat();
void UpdatePixelFormat();
const PixelBufferFormat& GetPixelFormat() const {
MOZ_ASSERT(mPixelFormat);
return *mPixelFormat;
}
bool IsFramebufferComplete(GLuint fb, GLenum* status = nullptr);
// Does not check completeness.
@ -3541,7 +3510,7 @@ public:
}
bool IsOffscreen() const {
return !!mScreen;
return mIsOffscreen;
}
GLScreenBuffer* Screen() const {
@ -3696,10 +3665,43 @@ protected:
public:
void FlushIfHeavyGLCallsSinceLastFlush();
static bool ShouldSpew();
static bool ShouldDumpExts();
void Readback(SharedSurface* src, gfx::DataSourceSurface* dest);
};
bool DoesStringMatch(const char* aString, const char *aWantedString);
void SplitByChar(const nsACString& str, const char delim,
std::vector<nsCString>* const out);
template<size_t N>
bool
MarkBitfieldByString(const nsACString& str, const char* (&markStrList)[N],
std::bitset<N>* const out_markList)
{
for (size_t i = 0; i < N; i++) {
if (str.Equals(markStrList[i])) {
(*out_markList)[i] = 1;
return true;
}
}
return false;
}
template<size_t N>
void
MarkBitfieldByStrings(const std::vector<nsCString>& strList,
bool dumpStrings, const char* (&markStrList)[N],
std::bitset<N>* const out_markList)
{
for (auto itr = strList.begin(); itr != strList.end(); ++itr) {
const nsACString& str = *itr;
const bool wasMarked = MarkBitfieldByString(str, markStrList,
out_markList);
if (dumpStrings)
printf_stderr(" %s%s\n", str.BeginReading(), wasMarked ? "(*)" : "");
}
}
} /* namespace gl */
} /* namespace mozilla */

View File

@ -28,10 +28,8 @@ class GLContextCGL : public GLContext
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL, MOZ_OVERRIDE)
GLContextCGL(const SurfaceCaps& caps,
GLContext *shareContext,
NSOpenGLContext *context,
bool isOffscreen = false);
GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context,
bool isOffscreen, ContextProfile profile);
~GLContextCGL();

View File

@ -274,6 +274,16 @@ static const FeatureInfo sFeatureInfoArr[] = {
* ARB_occlusion_query (added by OpenGL 2.0).
*/
},
{
"get_string_indexed",
GLVersion::GL3,
GLESVersion::ES3,
GLContext::Extension_None,
{
GLContext::Extensions_End
}
// glGetStringi
},
{
"gpu_shader4",
GLVersion::GL3,

View File

@ -21,16 +21,14 @@ namespace gl {
using namespace mozilla::gfx;
static bool gUseDoubleBufferedWindows = true;
class CGLLibrary
{
public:
CGLLibrary()
: mInitialized(false),
mOGLLibrary(nullptr),
mPixelFormat(nullptr)
{ }
: mInitialized(false)
, mUseDoubleBufferedWindows(true)
, mOGLLibrary(nullptr)
{}
bool EnsureInitialized()
{
@ -46,48 +44,33 @@ public:
}
const char* db = PR_GetEnv("MOZ_CGL_DB");
gUseDoubleBufferedWindows = (!db || *db != '0');
if (db) {
mUseDoubleBufferedWindows = *db != '0';
}
mInitialized = true;
return true;
}
NSOpenGLPixelFormat *PixelFormat()
{
if (mPixelFormat == nullptr) {
NSOpenGLPixelFormatAttribute attribs[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAAllowOfflineRenderers,
NSOpenGLPFADoubleBuffer,
0
};
if (!gUseDoubleBufferedWindows) {
attribs[2] = 0;
}
mPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
}
return mPixelFormat;
bool UseDoubleBufferedWindows() const {
MOZ_ASSERT(mInitialized);
return mUseDoubleBufferedWindows;
}
private:
bool mInitialized;
bool mUseDoubleBufferedWindows;
PRLibrary *mOGLLibrary;
NSOpenGLPixelFormat *mPixelFormat;
};
CGLLibrary sCGLLibrary;
GLContextCGL::GLContextCGL(
const SurfaceCaps& caps,
GLContext *shareContext,
NSOpenGLContext *context,
bool isOffscreen)
: GLContext(caps, shareContext, isOffscreen),
mContext(context)
GLContextCGL::GLContextCGL(const SurfaceCaps& caps, NSOpenGLContext* context,
bool isOffscreen, ContextProfile profile)
: GLContext(caps, nullptr, isOffscreen)
, mContext(context)
{
SetProfileVersion(ContextProfile::OpenGLCompatibility, 210);
SetProfileVersion(profile, 210);
}
GLContextCGL::~GLContextCGL()
@ -162,7 +145,7 @@ GLContextCGL::SetupLookupFunction()
bool
GLContextCGL::IsDoubleBuffered() const
{
return gUseDoubleBufferedWindows;
return sCGLLibrary.UseDoubleBufferedWindows();
}
bool
@ -182,26 +165,66 @@ GLContextCGL::SwapBuffers()
}
static GLContextCGL *
GetGlobalContextCGL()
{
return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateWrappingExisting(void*, void*)
{
return nullptr;
}
static const NSOpenGLPixelFormatAttribute kAttribs_singleBuffered[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAAllowOfflineRenderers,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_doubleBuffered[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAAllowOfflineRenderers,
NSOpenGLPFADoubleBuffer,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen[] = {
NSOpenGLPFAPixelBuffer,
0
};
static const NSOpenGLPixelFormatAttribute kAttribs_offscreen_coreProfile[] = {
NSOpenGLPFAAccelerated,
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
0
};
static NSOpenGLContext*
CreateWithFormat(const NSOpenGLPixelFormatAttribute* attribs)
{
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]
initWithAttributes:attribs];
if (!format)
return nullptr;
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format
shareContext:nullptr];
[format release];
return context;
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
{
GLContextCGL *shareContext = GetGlobalContextCGL();
if (!sCGLLibrary.EnsureInitialized()) {
return nullptr;
}
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:sCGLLibrary.PixelFormat()
shareContext:(shareContext ? shareContext->mContext : NULL)];
const NSOpenGLPixelFormatAttribute* attribs;
if (sCGLLibrary.UseDoubleBufferedWindows()) {
attribs = kAttribs_doubleBuffered;
} else {
attribs = kAttribs_singleBuffered;
}
NSOpenGLContext* context = CreateWithFormat(attribs);
if (!context) {
return nullptr;
}
@ -211,10 +234,13 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
[context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
SurfaceCaps caps = SurfaceCaps::ForRGBA();
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps,
shareContext,
context);
ContextProfile profile = ContextProfile::OpenGLCompatibility;
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(caps, context, false,
profile);
if (!glContext->Init()) {
glContext = nullptr;
[context release];
return nullptr;
}
@ -222,49 +248,54 @@ GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
}
static already_AddRefed<GLContextCGL>
CreateOffscreenFBOContext(bool aShare = true)
CreateOffscreenFBOContext(bool requireCompatProfile)
{
if (!sCGLLibrary.EnsureInitialized()) {
return nullptr;
}
GLContextCGL *shareContext = aShare ? GetGlobalContextCGL() : nullptr;
if (aShare && !shareContext) {
// if there is no share context, then we can't use FBOs.
return nullptr;
}
ContextProfile profile;
NSOpenGLContext* context = nullptr;
NSOpenGLContext *context = [[NSOpenGLContext alloc]
initWithFormat:sCGLLibrary.PixelFormat()
shareContext:shareContext ? shareContext->GetNSOpenGLContext() : NULL];
if (!requireCompatProfile) {
profile = ContextProfile::OpenGLCore;
context = CreateWithFormat(kAttribs_offscreen_coreProfile);
}
if (!context) {
profile = ContextProfile::OpenGLCompatibility;
context = CreateWithFormat(kAttribs_offscreen);
}
if (!context) {
return nullptr;
}
SurfaceCaps dummyCaps = SurfaceCaps::Any();
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, shareContext, context, true);
nsRefPtr<GLContextCGL> glContext = new GLContextCGL(dummyCaps, context,
true, profile);
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateHeadless()
GLContextProviderCGL::CreateHeadless(bool requireCompatProfile)
{
nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
if (!glContext)
nsRefPtr<GLContextCGL> gl;
gl = CreateOffscreenFBOContext(requireCompatProfile);
if (!gl)
return nullptr;
if (!glContext->Init())
if (!gl->Init())
return nullptr;
return glContext.forget();
return gl.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext->InitOffscreen(ToIntSize(size), caps))
return nullptr;
@ -299,7 +330,7 @@ GLContextProviderCGL::GetGlobalContext()
void
GLContextProviderCGL::Shutdown()
{
gGlobalContext = nullptr;
gGlobalContext = nullptr;
}
} /* namespace gl */

View File

@ -878,7 +878,7 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
}
already_AddRefed<GLContext>
GLContextProviderEGL::CreateHeadless()
GLContextProviderEGL::CreateHeadless(bool)
{
if (!sEGLLibrary.EnsureInitialized()) {
return nullptr;
@ -897,9 +897,10 @@ GLContextProviderEGL::CreateHeadless()
// often without the ability to texture from them directly.
already_AddRefed<GLContext>
GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext)
return nullptr;

View File

@ -1215,7 +1215,7 @@ DONE_CREATING_PIXMAP:
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateHeadless()
GLContextProviderGLX::CreateHeadless(bool)
{
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize);
@ -1227,9 +1227,10 @@ GLContextProviderGLX::CreateHeadless()
already_AddRefed<GLContext>
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext)
return nullptr;

View File

@ -58,11 +58,12 @@ public:
*/
static already_AddRefed<GLContext>
CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps);
const SurfaceCaps& caps,
bool requireCompatProfile);
// Just create a context. We'll add offscreen stuff ourselves.
static already_AddRefed<GLContext>
CreateHeadless();
CreateHeadless(bool requireCompatProfile);
/**
* Create wrapping Gecko GLContext for external gl context.

View File

@ -22,13 +22,14 @@ GLContextProviderNull::CreateWrappingExisting(void*, void*)
already_AddRefed<GLContext>
GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
const SurfaceCaps&)
const SurfaceCaps&,
bool)
{
return nullptr;
}
already_AddRefed<GLContext>
GLContextProviderNull::CreateHeadless()
GLContextProviderNull::CreateHeadless(bool)
{
return nullptr;
}

View File

@ -607,7 +607,7 @@ CreateWindowOffscreenContext()
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateHeadless()
GLContextProviderWGL::CreateHeadless(bool)
{
if (!sWGLLib.EnsureInitialized()) {
return nullptr;
@ -641,9 +641,10 @@ GLContextProviderWGL::CreateHeadless()
already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
const SurfaceCaps& caps,
bool requireCompatProfile)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
if (!glContext)
return nullptr;

View File

@ -666,6 +666,10 @@ struct GLContextSymbols
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize, const GLvoid* data);
PFNGLCOMPRESSEDTEXSUBIMAGE3D fCompressedTexSubImage3D;
// get_string_indexed
typedef const GLubyte* (GLAPIENTRY * pfnGLGetStringiT)(GLenum name, GLuint index);
pfnGLGetStringiT fGetStringi;
};
}

View File

@ -12,8 +12,3 @@ GLFormats::GLFormats()
{
std::memset(this, 0, sizeof(GLFormats));
}
PixelBufferFormat::PixelBufferFormat()
{
std::memset(this, 0, sizeof(PixelBufferFormat));
}

View File

@ -43,19 +43,6 @@ struct GLFormats
GLsizei samples;
};
struct PixelBufferFormat
{
// Constructs a zeroed object:
PixelBufferFormat();
int red, green, blue;
int alpha;
int depth, stencil;
int samples;
int ColorBits() const { return red + green + blue; }
};
} /* namespace gl */
} /* namespace mozilla */

View File

@ -35,8 +35,7 @@ static const char *sEGLExtensionNames[] = {
"EGL_EXT_create_context_robustness",
"EGL_KHR_image",
"EGL_KHR_fence_sync",
"EGL_ANDROID_native_fence_sync",
nullptr
"EGL_ANDROID_native_fence_sync"
};
#if defined(ANDROID)
@ -240,8 +239,8 @@ GLLibraryEGL::EnsureInitialized()
};
// Do not warn about the failure to load this - see bug 1092191
GLLibraryLoader::LoadSymbols(mEGLLibrary, &optionalSymbols[0],
nullptr, nullptr, false);
GLLibraryLoader::LoadSymbols(mEGLLibrary, &optionalSymbols[0], nullptr, nullptr,
false);
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
MOZ_RELEASE_ASSERT(mSymbols.fQueryStringImplementationANDROID,
@ -421,15 +420,24 @@ GLLibraryEGL::EnsureInitialized()
void
GLLibraryEGL::InitExtensions()
{
const char *extensions = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
std::vector<nsCString> driverExtensionList;
if (!extensions) {
const char* rawExts = (const char*)fQueryString(mEGLDisplay, LOCAL_EGL_EXTENSIONS);
if (rawExts) {
nsDependentCString exts(rawExts);
SplitByChar(exts, ' ', &driverExtensionList);
} else {
NS_WARNING("Failed to load EGL extension list!");
return;
}
GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions,
sEGLExtensionNames);
const bool shouldDumpExts = GLContext::ShouldDumpExts();
if (shouldDumpExts) {
printf_stderr("%i EGL driver extensions: (*: recognized)\n",
(uint32_t)driverExtensionList.size());
}
MarkBitfieldByStrings(driverExtensionList, shouldDumpExts, sEGLExtensionNames,
&mAvailableExtensions);
}
void

View File

@ -15,6 +15,7 @@
#include "GeckoProfiler.h"
#include <bitset>
#include <vector>
#if defined(XP_WIN)

View File

@ -517,43 +517,6 @@ GLScreenBuffer::CreateRead(SharedSurface* surf)
return ReadBuffer::Create(gl, caps, formats, surf);
}
void
GLScreenBuffer::Readback(SharedSurface* src, gfx::DataSourceSurface* dest)
{
MOZ_ASSERT(src && dest);
MOZ_ASSERT(dest->GetSize() == src->mSize);
MOZ_ASSERT(dest->GetFormat() == (src->mHasAlpha ? SurfaceFormat::B8G8R8A8
: SurfaceFormat::B8G8R8X8));
mGL->MakeCurrent();
bool needsSwap = src != SharedSurf();
if (needsSwap) {
SharedSurf()->UnlockProd();
src->LockProd();
}
{
// Even though we're reading. We're doing it on
// the producer side. So we call ProducerAcquire
// instead of ConsumerAcquire.
src->ProducerAcquire();
UniquePtr<ReadBuffer> buffer = CreateRead(src);
MOZ_ASSERT(buffer);
ScopedBindFramebuffer autoFB(mGL, buffer->mFB);
ReadPixelsIntoDataSurface(mGL, dest);
src->ProducerRelease();
}
if (needsSwap) {
src->UnlockProd();
SharedSurf()->LockProd();
}
}
bool
GLScreenBuffer::IsDrawFramebufferDefault() const
{

View File

@ -245,8 +245,6 @@ public:
bool Resize(const gfx::IntSize& size);
void Readback(SharedSurface* src, gfx::DataSourceSurface* dest);
protected:
bool Attach(SharedSurface* surf, const gfx::IntSize& size);

View File

@ -135,7 +135,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
if (destSize == readSize && destFormat == format) {
RefPtr<DataSourceSurface> data =
Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
mGLContext->Screen()->Readback(frontbuffer, data);
mGLContext->Readback(frontbuffer, data);
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(data, data);
}
@ -154,7 +154,7 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
}
// Readback handles Flush/MarkDirty.
mGLContext->Screen()->Readback(frontbuffer, resultSurf);
mGLContext->Readback(frontbuffer, resultSurf);
if (needsPremult) {
gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
}

View File

@ -39,7 +39,7 @@ GLImage::GetAsSourceSurface()
MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread");
if (!sSnapshotContext) {
sSnapshotContext = GLContextProvider::CreateHeadless();
sSnapshotContext = GLContextProvider::CreateHeadless(false);
if (!sSnapshotContext) {
NS_WARNING("Failed to create snapshot GLContext");
return nullptr;

View File

@ -124,8 +124,11 @@ CompositorOGL::CreateContext()
SurfaceCaps caps = SurfaceCaps::ForRGB();
caps.preserve = false;
caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == gfxImageFormat::RGB16_565;
bool requireCompatProfile = true;
context = GLContextProvider::CreateOffscreen(gfxIntSize(mSurfaceSize.width,
mSurfaceSize.height), caps);
mSurfaceSize.height),
caps, requireCompatProfile);
}
if (!context)

View File

@ -45,7 +45,7 @@ public:
caps.preserve = false;
caps.bpp16 = false;
nsRefPtr<GLContext> context = GLContextProvider::CreateOffscreen(
gfxIntSize(gCompWidth, gCompHeight), caps);
gfxIntSize(gCompWidth, gCompHeight), caps, true);
return context.forget().take();
}
return nullptr;

View File

@ -1097,8 +1097,9 @@ gfxPlatform::GetSkiaGLGlue()
* FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
* stands, this only works on the main thread.
*/
mozilla::gl::SurfaceCaps caps = mozilla::gl::SurfaceCaps::ForRGBA();
nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
bool requireCompatProfile = true;
nsRefPtr<mozilla::gl::GLContext> glContext;
glContext = mozilla::gl::GLContextProvider::CreateHeadless(requireCompatProfile);
if (!glContext) {
printf_stderr("Failed to create GLContext for SkiaGL!\n");
return nullptr;

View File

@ -72,8 +72,8 @@ public:
}
nsRefPtr<gl::GLContext> gl;
gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16),
gl::SurfaceCaps::ForRGB());
bool requireCompatProfile = true;
gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile);
if (!gl) {
// Setting mReady to true here means that we won't retry. Everything will