зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1094457 - Implement ReadBuffer and RenderbufferStorageMultisample. - r=kamidphish
This commit is contained in:
Родитель
40b914bc13
Коммит
e9a175ca67
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче