Bug 1094457 - Implement ReadBuffer and RenderbufferStorageMultisample. - r=kamidphish

This commit is contained in:
Jeff Gilbert 2015-02-18 16:57:05 -08:00
Родитель 40b914bc13
Коммит e9a175ca67
15 изменённых файлов: 338 добавлений и 100 удалений

Просмотреть файл

@ -459,12 +459,45 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
void
WebGL2Context::ReadBuffer(GLenum mode)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
MakeContextCurrent();
if (mBoundReadFramebuffer) {
bool isColorAttachment = (mode >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mode <= LastColorAttachment());
if (mode != LOCAL_GL_NONE &&
!isColorAttachment)
{
ErrorInvalidEnumInfo("readBuffer: If READ_FRAMEBUFFER is non-null,"
" `mode` must be COLOR_ATTACHMENTN or NONE."
" Was:", mode);
return;
}
gl->fReadBuffer(mode);
return;
}
// Operating on the default framebuffer.
if (mode != LOCAL_GL_NONE &&
mode != LOCAL_GL_BACK)
{
ErrorInvalidEnumInfo("readBuffer: If READ_FRAMEBUFFER is null, `mode`"
" must be BACK or NONE. Was:", mode);
return;
}
gl->Screen()->SetReadBuffer(mode);
}
void
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
GLenum internalFormat,
GLsizei width, GLsizei height)
{
MOZ_CRASH("Not Implemented.");
RenderbufferStorage_base("renderbufferStorageMultisample", target, samples,
internalFormat, width, height);
}

Просмотреть файл

@ -203,6 +203,7 @@ WebGLContextOptions::WebGLContextOptions()
WebGLContext::WebGLContext()
: WebGLContextUnchecked(nullptr)
, mBypassShaderValidation(false)
, mGLMaxSamples(1)
, mNeedsFakeNoAlpha(false)
{
mGeneration = 0;
@ -1721,6 +1722,7 @@ WebGLContext::GetSurfaceSnapshot(bool* out_premultAlpha)
{
ScopedBindFramebuffer autoFB(gl, 0);
ClearBackbufferIfNeeded();
// TODO: Save, override, then restore glReadBuffer if present.
ReadPixelsIntoDataSurface(gl, surf);
}

Просмотреть файл

@ -254,7 +254,9 @@ public:
void ErrorInvalidOperation(const char* fmt = 0, ...);
void ErrorInvalidValue(const char* fmt = 0, ...);
void ErrorInvalidFramebufferOperation(const char* fmt = 0, ...);
void ErrorInvalidEnumInfo(const char* info, GLenum enumvalue);
void ErrorInvalidEnumInfo(const char* info, GLenum enumValue);
void ErrorInvalidEnumInfo(const char* info, const char* funcName,
GLenum enumValue);
void ErrorOutOfMemory(const char* fmt = 0, ...);
const char* ErrorName(GLenum error);
@ -531,6 +533,11 @@ public:
ErrorResult& rv);
void RenderbufferStorage(GLenum target, GLenum internalFormat,
GLsizei width, GLsizei height);
protected:
void RenderbufferStorage_base(const char* funcName, GLenum target,
GLsizei samples, GLenum internalformat,
GLsizei width, GLsizei height);
public:
void SampleCoverage(GLclampf value, WebGLboolean invert);
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
void ShaderSource(WebGLShader* shader, const nsAString& source);
@ -1146,8 +1153,9 @@ protected:
int32_t mGLMaxVertexUniformVectors;
int32_t mGLMaxColorAttachments;
int32_t mGLMaxDrawBuffers;
GLuint mGLMaxTransformFeedbackSeparateAttribs;
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
GLuint mGLMaxUniformBufferBindings;
GLsizei mGLMaxSamples;
public:
GLuint MaxVertexAttribs() const {
@ -1422,6 +1430,10 @@ protected:
uint32_t mMaxFramebufferColorAttachments;
GLenum LastColorAttachment() const {
return LOCAL_GL_COLOR_ATTACHMENT0 + mMaxFramebufferColorAttachments - 1;
}
bool ValidateFramebufferTarget(GLenum target, const char* const info);
WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;

Просмотреть файл

@ -1970,33 +1970,28 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
}
bool isSourceTypeFloat = false;
if (mBoundReadFramebuffer &&
mBoundReadFramebuffer->ColorAttachmentCount() &&
mBoundReadFramebuffer->ColorAttachment(0).IsDefined())
{
isSourceTypeFloat = mBoundReadFramebuffer->ColorAttachment(0).IsReadableFloat();
MakeContextCurrent();
bool isSourceTypeFloat;
if (mBoundReadFramebuffer) {
TexInternalFormat srcFormat;
if (!mBoundReadFramebuffer->ValidateForRead("readPixels", &srcFormat))
return;
MOZ_ASSERT(srcFormat != LOCAL_GL_NONE);
TexType type = TypeFromInternalFormat(srcFormat);
isSourceTypeFloat = (type == LOCAL_GL_FLOAT ||
type == LOCAL_GL_HALF_FLOAT);
} else {
ClearBackbufferIfNeeded();
isSourceTypeFloat = false;
}
if (isReadTypeFloat != isSourceTypeFloat)
return ErrorInvalidOperation("readPixels: Invalid type floatness");
// Check the format and type params to assure they are an acceptable pair (as per spec)
MakeContextCurrent();
if (mBoundReadFramebuffer) {
// prevent readback of arbitrary video memory through uninitialized renderbuffers!
if (!mBoundReadFramebuffer->CheckAndInitializeAttachments())
return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
" correct color/depth/stencil type.");
}
} else {
ClearBackbufferIfNeeded();
}
bool isFormatAndTypeValid = false;
@ -2128,95 +2123,156 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
}
void
WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target,
GLsizei samples,
GLenum internalFormat, GLsizei width,
GLsizei height)
{
if (IsContextLost())
return;
if (!mBoundRenderbuffer)
return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
if (!mBoundRenderbuffer) {
ErrorInvalidOperation("%s: Called on renderbuffer 0.", funcName);
return;
}
if (target != LOCAL_GL_RENDERBUFFER)
return ErrorInvalidEnumInfo("renderbufferStorage: target", target);
if (target != LOCAL_GL_RENDERBUFFER) {
ErrorInvalidEnumInfo("`target`", funcName, target);
return;
}
if (width < 0 || height < 0)
return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0");
if (samples < 0 || samples > mGLMaxSamples) {
ErrorInvalidValue("%s: `samples` is out of the valid range.", funcName);
return;
}
if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize)
return ErrorInvalidValue("renderbufferStorage: width or height exceeds maximum renderbuffer size");
if (width < 0 || height < 0) {
ErrorInvalidValue("%s: Width and height must be >= 0.", funcName);
return;
}
if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize) {
ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
" size.", funcName);
return;
}
bool isFormatValid = false;
switch (internalFormat) {
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
case LOCAL_GL_RGB565:
case LOCAL_GL_DEPTH_COMPONENT16:
case LOCAL_GL_STENCIL_INDEX8:
case LOCAL_GL_DEPTH_STENCIL:
isFormatValid = true;
break;
case LOCAL_GL_SRGB8_ALPHA8_EXT:
if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
isFormatValid = true;
break;
case LOCAL_GL_RGB16F:
case LOCAL_GL_RGBA16F:
if (IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float) &&
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
{
isFormatValid = true;
}
break;
case LOCAL_GL_RGB32F:
case LOCAL_GL_RGBA32F:
if (IsExtensionEnabled(WebGLExtensionID::OES_texture_float) &&
IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
{
isFormatValid = true;
}
break;
default:
break;
}
if (!isFormatValid) {
ErrorInvalidEnumInfo("`internalFormat`", funcName, internalFormat);
return;
}
// certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
GLenum internalformatForGL = internalformat;
GLenum internalFormatForGL = internalFormat;
switch (internalformat) {
switch (internalFormat) {
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
// 16-bit RGBA formats are not supported on desktop GL
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8;
if (!gl->IsGLES())
internalFormatForGL = LOCAL_GL_RGBA8;
break;
case LOCAL_GL_RGB565:
// the RGB565 format is not supported on desktop GL
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8;
if (!gl->IsGLES())
internalFormatForGL = LOCAL_GL_RGB8;
break;
case LOCAL_GL_DEPTH_COMPONENT16:
if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
internalFormatForGL = LOCAL_GL_DEPTH_COMPONENT24;
else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
break;
case LOCAL_GL_STENCIL_INDEX8:
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
break;
case LOCAL_GL_DEPTH_STENCIL:
// We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
break;
case LOCAL_GL_SRGB8_ALPHA8_EXT:
break;
case LOCAL_GL_RGB16F:
case LOCAL_GL_RGBA16F: {
bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float) &&
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float);
if (!hasExtensions)
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
break;
}
case LOCAL_GL_RGB32F:
case LOCAL_GL_RGBA32F: {
bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_float) &&
IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float);
if (!hasExtensions)
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
break;
}
default:
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
break;
}
// Validation complete.
MakeContextCurrent();
bool sizeChanges = width != mBoundRenderbuffer->Width() ||
height != mBoundRenderbuffer->Height() ||
internalformat != mBoundRenderbuffer->InternalFormat();
if (sizeChanges) {
bool willRealloc = samples != mBoundRenderbuffer->Samples() ||
internalFormat != mBoundRenderbuffer->InternalFormat() ||
width != mBoundRenderbuffer->Width() ||
height != mBoundRenderbuffer->Height();
if (willRealloc) {
// Invalidate framebuffer status cache
mBoundRenderbuffer->NotifyFBsStatusChanged();
GetAndFlushUnderlyingGLErrors();
mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
mBoundRenderbuffer->RenderbufferStorage(samples, internalFormatForGL,
width, height);
GLenum error = GetAndFlushUnderlyingGLErrors();
if (error) {
GenerateWarning("renderbufferStorage generated error %s", ErrorName(error));
GenerateWarning("%s generated error %s", funcName,
ErrorName(error));
return;
}
} else {
mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
mBoundRenderbuffer->RenderbufferStorage(samples, internalFormatForGL,
width, height);
}
mBoundRenderbuffer->SetInternalFormat(internalformat);
mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
mBoundRenderbuffer->SetSamples(samples);
mBoundRenderbuffer->SetInternalFormat(internalFormat);
mBoundRenderbuffer->SetInternalFormatForGL(internalFormatForGL);
mBoundRenderbuffer->setDimensions(width, height);
mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData);
}
void
WebGLContext::RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
{
RenderbufferStorage_base("renderbufferStorage", target, 0,
internalFormat, width, height);
}
void
WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
{

Просмотреть файл

@ -501,12 +501,23 @@ WebGLContext::ErrorInvalidEnum(const char* fmt, ...)
}
void
WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumvalue)
WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue)
{
nsCString name;
EnumName(enumvalue, &name);
EnumName(enumValue, &name);
return ErrorInvalidEnum("%s: invalid enum value %s", info, name.get());
return ErrorInvalidEnum("%s: invalid enum value %s", info, name.BeginReading());
}
void
WebGLContext::ErrorInvalidEnumInfo(const char* info, const char* funcName,
GLenum enumValue)
{
nsCString name;
EnumName(enumValue, &name);
ErrorInvalidEnum("%s: %s: Invalid enum: 0x%04x (%s).", funcName, info,
enumValue, name.BeginReading());
}
void

Просмотреть файл

@ -1286,25 +1286,11 @@ WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func,
GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
if (mBoundReadFramebuffer) {
if (!mBoundReadFramebuffer->CheckAndInitializeAttachments()) {
ErrorInvalidFramebufferOperation("%s: Incomplete framebuffer.",
InfoFrom(func, dims));
TexInternalFormat srcFormat;
if (!mBoundReadFramebuffer->ValidateForRead(InfoFrom(func, dims), &srcFormat))
return false;
}
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
ErrorInvalidOperation("%s: Read source attachment doesn't have the"
" correct color/depth/stencil type.",
InfoFrom(func, dims));
return false;
}
// Get the correct format for the framebuffer, as it's not the default one.
const WebGLFramebuffer::Attachment& color0 =
mBoundReadFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
fboFormat = mBoundReadFramebuffer->GetFormatForAttachment(color0);
fboFormat = srcFormat.get();
}
// Make sure the format of the framebuffer is a superset of the format
@ -1818,12 +1804,16 @@ WebGLContext::InitAndValidateGL()
mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
mGLMaxSamples = 1;
} else {
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
if (!gl->GetPotentialInteger(LOCAL_GL_MAX_SAMPLES, (GLint*)&mGLMaxSamples))
mGLMaxSamples = 1;
}
// Calculate log2 of mGLMaxTextureSize and mGLMaxCubeMapTextureSize

Просмотреть файл

@ -28,6 +28,7 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
, mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
, mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
, mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
, mReadBufferMode(LOCAL_GL_COLOR_ATTACHMENT0)
{
mContext->mFramebuffers.insertBack(this);
@ -977,6 +978,38 @@ WebGLFramebuffer::FinalizeAttachments() const
FinalizeDrawAndReadBuffers(gl, ColorAttachment(0).IsDefined());
}
bool
WebGLFramebuffer::ValidateForRead(const char* info, TexInternalFormat* const out_format)
{
if (mReadBufferMode == LOCAL_GL_NONE) {
mContext->ErrorInvalidOperation("%s: Read buffer mode must not be"
" NONE.", info);
return false;
}
const auto& attachment = GetAttachment(mReadBufferMode);
if (!CheckAndInitializeAttachments()) {
mContext->ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
return false;
}
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
if (!HasCompletePlanes(readPlaneBits)) {
mContext->ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
" correct color/depth/stencil type.");
return false;
}
if (!attachment.IsDefined()) {
mContext->ErrorInvalidOperation("readPixels: ");
return false;
}
*out_format = attachment.EffectiveInternalFormat();
return true;
}
inline void
ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& field)
{

Просмотреть файл

@ -174,6 +174,8 @@ public:
void NotifyAttachableChanged() const;
bool ValidateForRead(const char* info, TexInternalFormat* const out_format);
private:
~WebGLFramebuffer() {
DeleteOnce();
@ -187,6 +189,7 @@ private:
Attachment mDepthAttachment;
Attachment mStencilAttachment;
Attachment mDepthStencilAttachment;
GLenum mReadBufferMode;
};
} // namespace mozilla

Просмотреть файл

@ -54,6 +54,7 @@ WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
, mInternalFormat(0)
, mInternalFormatForGL(0)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
, mSamples(1)
{
mContext->MakeContextCurrent();
@ -156,11 +157,30 @@ WebGLRenderbuffer::BindRenderbuffer() const
mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
}
static void
RenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
GLenum internalFormat, GLsizei width,
GLsizei height)
{
MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample));
MOZ_ASSERT(samples >= 0);
MOZ_ASSERT(samples <= gl->MaxSamples());
if (samples > 0) {
gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
internalFormat, width, height);
} else {
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width,
height);
}
}
void
WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width,
GLsizei height) const
WebGLRenderbuffer::RenderbufferStorage(GLsizei samples, GLenum internalFormat,
GLsizei width, GLsizei height) const
{
gl::GLContext* gl = mContext->gl;
MOZ_ASSERT(samples >= 0 && samples <= 256); // Sanity check.
GLenum primaryFormat = internalFormat;
GLenum secondaryFormat = 0;
@ -170,7 +190,8 @@ WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width,
secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
}
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, primaryFormat, width, height);
RenderbufferStorageMaybeMultisample(gl, samples, primaryFormat, width,
height);
if (!mSecondaryRB) {
MOZ_ASSERT(!secondaryFormat);
@ -182,9 +203,10 @@ WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width,
// non-depth-stencil attachment point.
gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
if (secondaryFormat) {
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, secondaryFormat, width, height);
RenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat, width,
height);
} else {
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA4, 1, 1);
RenderbufferStorageMaybeMultisample(gl, samples, LOCAL_GL_RGBA4, 1, 1);
}
}

Просмотреть файл

@ -38,6 +38,9 @@ public:
mImageDataStatus = x;
}
GLsizei Samples() const { return mSamples; }
void SetSamples(GLsizei samples) { mSamples = samples; }
GLenum InternalFormat() const { return mInternalFormat; }
void SetInternalFormat(GLenum internalFormat) {
mInternalFormat = internalFormat;
@ -55,8 +58,8 @@ public:
}
void BindRenderbuffer() const;
void RenderbufferStorage(GLenum internalFormat, GLsizei width,
GLsizei height) const;
void RenderbufferStorage(GLsizei samples, GLenum internalFormat,
GLsizei width, GLsizei height) const;
void FramebufferRenderbuffer(FBAttachment attachment) const;
// Only handles a subset of `pname`s.
GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
@ -76,6 +79,7 @@ protected:
GLenum mInternalFormat;
GLenum mInternalFormatForGL;
WebGLImageDataStatus mImageDataStatus;
GLsizei mSamples;
friend class WebGLFramebuffer;
};

Просмотреть файл

@ -1412,6 +1412,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsSupported(GLFeature::read_buffer)) {
SymLoadStruct extSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
END_SYMBOLS
};
if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
NS_ERROR("GL supports read_buffer without supplying its functions.");
MarkUnsupported(GLFeature::read_buffer);
ClearSymbols(extSymbols);
}
}
// Load developer symbols, don't fail if we can't find them.
SymLoadStruct auxSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },

Просмотреть файл

@ -115,6 +115,7 @@ enum class GLFeature {
occlusion_query2,
packed_depth_stencil,
query_objects,
read_buffer,
renderbuffer_color_float,
renderbuffer_color_half_float,
robustness,

Просмотреть файл

@ -408,6 +408,15 @@ static const FeatureInfo sFeatureInfoArr[] = {
* (added in OpenGL ES 3.0)
*/
},
{
"read_buffer",
GLVersion::GL2,
GLESVersion::ES3,
GLContext::Extension_None,
{
GLContext::Extensions_End
}
},
{
"renderbuffer_color_float",
GLVersion::GL3,

Просмотреть файл

@ -421,6 +421,12 @@ GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
// Check that we're all set up.
MOZ_ASSERT(SharedSurf() == surf);
// Update the ReadBuffer mode.
if (mGL->IsSupported(gl::GLFeature::read_buffer)) {
BindFB(0);
mRead->SetReadBuffer(mUserReadBufferMode);
}
return true;
}
@ -517,6 +523,16 @@ GLScreenBuffer::CreateRead(SharedSurface* surf)
return ReadBuffer::Create(gl, caps, formats, surf);
}
void
GLScreenBuffer::SetReadBuffer(GLenum mode)
{
MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::read_buffer));
MOZ_ASSERT(GetReadFB() == 0);
mUserReadBufferMode = mode;
mRead->SetReadBuffer(mUserReadBufferMode);
}
bool
GLScreenBuffer::IsDrawFramebufferDefault() const
{
@ -636,7 +652,6 @@ ReadBuffer::Create(GLContext* gl,
if (surf->mAttachType == AttachmentType::Screen) {
// Don't need anything. Our read buffer will be the 'screen'.
return UniquePtr<ReadBuffer>( new ReadBuffer(gl, 0, 0, 0,
surf) );
}
@ -740,5 +755,31 @@ ReadBuffer::Size() const
return mSurf->mSize;
}
void
ReadBuffer::SetReadBuffer(GLenum userMode) const
{
if (!mGL->IsSupported(GLFeature::read_buffer))
return;
GLenum internalMode;
switch (userMode) {
case LOCAL_GL_BACK:
internalMode = (mFB == 0) ? LOCAL_GL_BACK
: LOCAL_GL_COLOR_ATTACHMENT0;
break;
case LOCAL_GL_NONE:
internalMode = LOCAL_GL_NONE;
break;
default:
MOZ_CRASH("Bad value.");
}
mGL->MakeCurrent();
mGL->fReadBuffer(internalMode);
}
} /* namespace gl */
} /* namespace mozilla */

Просмотреть файл

@ -116,6 +116,8 @@ public:
SharedSurface* SharedSurf() const {
return mSurf;
}
void SetReadBuffer(GLenum mode) const;
};
@ -142,6 +144,8 @@ protected:
bool mNeedsBlit;
GLenum mUserReadBufferMode;
// Below are the parts that help us pretend to be framebuffer 0:
GLuint mUserDrawFB;
GLuint mUserReadFB;
@ -160,6 +164,7 @@ protected:
, mCaps(caps)
, mFactory(Move(factory))
, mNeedsBlit(true)
, mUserReadBufferMode(LOCAL_GL_BACK)
, mUserDrawFB(0)
, mUserReadFB(0)
, mInternalDrawFB(0)
@ -223,6 +228,8 @@ public:
void AfterDrawCall();
void BeforeReadCall();
void SetReadBuffer(GLenum userMode);
/**
* Attempts to read pixels from the current bound framebuffer, if
* it is backed by a SharedSurface.