Emulate RGB textures using BGRX IOSurfaces.

When the user requests an IOSurface Pbuffer with an RGB format, emulate the
missing alpha channel by clearing it to 1.0 and masking reads and writes in
shaders.

BUG=angleproject:3766

Change-Id: I58c992bf641d9ece0f923603f32640615150e4f3
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1737437
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
This commit is contained in:
Geoff Lang 2019-08-05 17:02:43 -04:00 коммит произвёл Commit Bot
Родитель 2251102112
Коммит b3eeb2a403
22 изменённых файлов: 333 добавлений и 131 удалений

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

@ -21,7 +21,7 @@ Status
Draft
Version
Version 2, Apr 1, 2019
Version 3, Aug 13, 2019
Number
@ -96,6 +96,7 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
GL_UNSIGNED_BYTE GL_RED
GL_UNSIGNED_SHORT GL_R16UI
GL_UNSIGNED_BYTE GL_RG
GL_UNSIGNED_BYTE GL_RGB
GL_UNSIGNED_BYTE GL_BGRA_EXT
GL_HALF_FLOAT GL_RGBA
---------------------------------------------------------------------------
@ -110,9 +111,14 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
Issues
There are no issues, please move on.
1. Can RGB formats be supported?
RESOLVED: Support for RGB internal formats is added in version 3. Surfaces
with an RGB format will ensure that the alpha channel of the IOSurface is
reset to 1.0 when it is used.
Revision History
Version 1, 2017/12/06 - first draft.
Version 2, 2019/04/01 - Allow MakeCurrent.
Version 3, 2019/08/13 - Allow RGB internal formats

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

@ -128,6 +128,18 @@ TextureTarget ImageIndex::getTarget() const
return TextureTypeToTarget(mType, mLayerIndex);
}
gl::TextureTarget ImageIndex::getTargetOrFirstCubeFace() const
{
if (isEntireLevelCubeMap())
{
return gl::kCubeMapTextureTargetMin;
}
else
{
return getTarget();
}
}
GLint ImageIndex::cubeMapFaceIndex() const
{
ASSERT(mType == TextureType::CubeMap);

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

@ -40,6 +40,8 @@ class ImageIndex
// map.
TextureTarget getTarget() const;
TextureTarget getTargetOrFirstCubeFace() const;
bool isLayered() const;
bool isEntireLevelCubeMap() const;

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

@ -926,6 +926,30 @@ angle::Result BlitGL::clearFramebuffer(FramebufferGL *source)
return angle::Result::Continue;
}
angle::Result BlitGL::clearRenderableTextureAlphaToOne(GLuint texture,
gl::TextureTarget target,
size_t level)
{
// Clearing the alpha of 3D textures is not supported/needed yet.
ASSERT(nativegl::UseTexImage2D(TextureTargetToType(target)));
ANGLE_TRY(initializeResources());
mStateManager->setClearColor(gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
mStateManager->setColorMask(false, false, false, true);
mStateManager->setScissorTestEnabled(false);
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(target),
texture, static_cast<GLint>(level));
mFunctions->clear(GL_COLOR_BUFFER_BIT);
// Unbind the texture from the the scratch framebuffer
mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0);
return angle::Result::Continue;
}
angle::Result BlitGL::initializeResources()
{
for (size_t i = 0; i < ArraySize(mScratchTextures); i++)

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

@ -126,6 +126,10 @@ class BlitGL : angle::NonCopyable
angle::Result clearFramebuffer(FramebufferGL *source);
angle::Result clearRenderableTextureAlphaToOne(GLuint texture,
gl::TextureTarget target,
size_t level);
angle::Result initializeResources();
private:

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

@ -73,7 +73,7 @@ FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data)
GLuint fbo = 0;
funcs->genFramebuffers(1, &fbo);
return new FramebufferGL(data, fbo, false);
return new FramebufferGL(data, fbo, false, false);
}
TextureImpl *ContextGL::createTexture(const gl::TextureState &state)

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

@ -218,12 +218,28 @@ bool RequiresMultiviewClear(const FramebufferState &state, bool scissorTestEnabl
return false;
}
bool IsEmulatedAlphaChannelTextureAttachment(const FramebufferAttachment *attachment)
{
if (!attachment || attachment->type() != GL_TEXTURE)
{
return false;
}
const Texture *texture = attachment->getTexture();
const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
return textureGL->hasEmulatedAlphaChannel(attachment->getTextureImageIndex());
}
} // namespace
FramebufferGL::FramebufferGL(const gl::FramebufferState &data, GLuint id, bool isDefault)
FramebufferGL::FramebufferGL(const gl::FramebufferState &data,
GLuint id,
bool isDefault,
bool emulatedAlpha)
: FramebufferImpl(data),
mFramebufferID(id),
mIsDefault(isDefault),
mHasEmulatedAlphaAttachment(emulatedAlpha),
mAppliedEnabledDrawBuffers(1)
{}
@ -1104,6 +1120,16 @@ angle::Result FramebufferGL::syncState(const gl::Context *context,
{
attachment = newAttachment;
}
// Hiding an alpha channel is only supported when it's the first attachment
// currently. Assert that these emulated textures are not bound to a framebuffer
// using MRT.
if (index == 0)
{
mHasEmulatedAlphaAttachment =
IsEmulatedAlphaChannelTextureAttachment(attachment);
}
ASSERT(index == 0 || !IsEmulatedAlphaChannelTextureAttachment(attachment));
}
break;
}
@ -1129,6 +1155,11 @@ bool FramebufferGL::isDefault() const
return mIsDefault;
}
bool FramebufferGL::hasEmulatedAlphaChannelTextureAttachment() const
{
return mHasEmulatedAlphaAttachment;
}
void FramebufferGL::syncClearState(const gl::Context *context, GLbitfield mask)
{
const FunctionsGL *functions = GetFunctionsGL(context);

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

@ -23,7 +23,7 @@ class StateManagerGL;
class FramebufferGL : public FramebufferImpl
{
public:
FramebufferGL(const gl::FramebufferState &data, GLuint id, bool isDefault);
FramebufferGL(const gl::FramebufferState &data, GLuint id, bool isDefault, bool emulatedAlpha);
~FramebufferGL() override;
void destroy(const gl::Context *context) override;
@ -88,6 +88,8 @@ class FramebufferGL : public FramebufferImpl
GLuint getFramebufferID() const;
bool isDefault() const;
bool hasEmulatedAlphaChannelTextureAttachment() const;
private:
void syncClearState(const gl::Context *context, GLbitfield mask);
void syncClearBufferState(const gl::Context *context, GLenum buffer, GLint drawBuffer);
@ -130,6 +132,8 @@ class FramebufferGL : public FramebufferImpl
GLuint mFramebufferID;
bool mIsDefault;
bool mHasEmulatedAlphaAttachment;
gl::DrawBufferMask mAppliedEnabledDrawBuffers;
};
} // namespace rx

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

@ -1489,15 +1489,6 @@ void StateManagerGL::syncState(const gl::Context *context,
{
const gl::State &state = context->getState();
// Changing the draw framebuffer binding sometimes requires resetting srgb blending.
if (glDirtyBits[gl::State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING])
{
if (mFunctions->standard == STANDARD_GL_DESKTOP)
{
mLocalDirtyBits.set(gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB);
}
}
const gl::State::DirtyBits glAndLocalDirtyBits = (glDirtyBits | mLocalDirtyBits) & bitMask;
if (!glAndLocalDirtyBits.any())
{
@ -1549,9 +1540,13 @@ void StateManagerGL::syncState(const gl::Context *context,
}
case gl::State::DIRTY_BIT_COLOR_MASK:
{
gl::Framebuffer *framebuffer = state.getDrawFramebuffer();
FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(framebuffer);
const auto &blendState = state.getBlendState();
setColorMask(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha);
setColorMaskForFramebuffer(blendState.colorMaskRed, blendState.colorMaskGreen,
blendState.colorMaskBlue, blendState.colorMaskAlpha,
framebufferGL);
break;
}
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
@ -1697,6 +1692,16 @@ void StateManagerGL::syncState(const gl::Context *context,
{
updateMultiviewBaseViewLayerIndexUniform(program, framebufferGL->getState());
}
// Changing the draw framebuffer binding sometimes requires resetting srgb blending.
if (mFunctions->standard == STANDARD_GL_DESKTOP)
{
iter.setLaterBit(gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB);
}
// If the framebuffer is emulating RGB on top of RGBA, the color mask has to be
// updated
iter.setLaterBit(gl::State::DIRTY_BIT_COLOR_MASK);
break;
}
case gl::State::DIRTY_BIT_RENDERBUFFER_BINDING:
@ -1888,6 +1893,20 @@ void StateManagerGL::setFramebufferSRGBEnabledForFramebuffer(const gl::Context *
}
}
void StateManagerGL::setColorMaskForFramebuffer(bool red,
bool green,
bool blue,
bool alpha,
const FramebufferGL *framebuffer)
{
bool modifiedAlphaMask = alpha;
if (framebuffer->hasEmulatedAlphaChannelTextureAttachment())
{
modifiedAlphaMask = false;
}
setColorMask(red, green, blue, modifiedAlphaMask);
}
void StateManagerGL::setDitherEnabled(bool enabled)
{
if (mDitherEnabled != enabled)

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

@ -136,6 +136,11 @@ class StateManagerGL final : angle::NonCopyable
void setFramebufferSRGBEnabledForFramebuffer(const gl::Context *context,
bool enabled,
const FramebufferGL *framebuffer);
void setColorMaskForFramebuffer(bool red,
bool green,
bool blue,
bool alpha,
const FramebufferGL *framebuffer);
void setDitherEnabled(bool enabled);

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

@ -25,7 +25,7 @@ SurfaceGL::~SurfaceGL() {}
FramebufferImpl *SurfaceGL::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &data)
{
return new FramebufferGL(data, 0, true);
return new FramebufferGL(data, 0, true, false);
}
egl::Error SurfaceGL::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
@ -46,4 +46,9 @@ angle::Result SurfaceGL::initializeContents(const gl::Context *context,
return angle::Result::Continue;
}
bool SurfaceGL::hasEmulatedAlphaChannel() const
{
return false;
}
} // namespace rx

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

@ -26,6 +26,8 @@ class SurfaceGL : public SurfaceImpl
angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override;
virtual bool hasEmulatedAlphaChannel() const;
};
} // namespace rx

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

@ -14,6 +14,7 @@
#include "libANGLE/Context.h"
#include "libANGLE/MemoryObject.h"
#include "libANGLE/State.h"
#include "libANGLE/Surface.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/queryconversions.h"
@ -25,6 +26,7 @@
#include "libANGLE/renderer/gl/ImageGL.h"
#include "libANGLE/renderer/gl/MemoryObjectGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/SurfaceGL.h"
#include "libANGLE/renderer/gl/formatutilsgl.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
#include "platform/FeaturesGL.h"
@ -72,7 +74,7 @@ LevelInfoGL GetLevelInfo(GLenum originalInternalFormat, GLenum destinationIntern
GLenum destinationFormat = gl::GetUnsizedFormat(destinationInternalFormat);
return LevelInfoGL(originalFormat, destinationInternalFormat,
GetDepthStencilWorkaround(originalFormat),
GetLUMAWorkaroundInfo(originalFormat, destinationFormat));
GetLUMAWorkaroundInfo(originalFormat, destinationFormat), false);
}
gl::Texture::DirtyBits GetLevelWorkaroundDirtyBits()
@ -108,16 +110,18 @@ LUMAWorkaroundGL::LUMAWorkaroundGL(bool enabled_, GLenum workaroundFormat_)
: enabled(enabled_), workaroundFormat(workaroundFormat_)
{}
LevelInfoGL::LevelInfoGL() : LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL()) {}
LevelInfoGL::LevelInfoGL() : LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL(), false) {}
LevelInfoGL::LevelInfoGL(GLenum sourceFormat_,
GLenum nativeInternalFormat_,
bool depthStencilWorkaround_,
const LUMAWorkaroundGL &lumaWorkaround_)
const LUMAWorkaroundGL &lumaWorkaround_,
bool emulatedAlphaChannel_)
: sourceFormat(sourceFormat_),
nativeInternalFormat(nativeInternalFormat_),
depthStencilWorkaround(depthStencilWorkaround_),
lumaWorkaround(lumaWorkaround_)
lumaWorkaround(lumaWorkaround_),
emulatedAlphaChannel(emulatedAlphaChannel_)
{}
TextureGL::TextureGL(const gl::TextureState &state, GLuint id)
@ -1177,7 +1181,11 @@ angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *
// Make sure this texture is bound
stateManager->bindTexture(getType(), mTextureID);
setLevelInfo(context, getType(), 0, 1, LevelInfoGL());
SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
setLevelInfo(context, getType(), 0, 1,
LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL(),
surfaceGL->hasEmulatedAlphaChannel()));
return angle::Result::Continue;
}
@ -1484,6 +1492,12 @@ GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
}
bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
{
return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
.emulatedAlphaChannel;
}
void TextureGL::syncTextureStateSwizzle(const gl::Context *context,
const FunctionsGL *functions,
GLenum name,
@ -1492,107 +1506,110 @@ void TextureGL::syncTextureStateSwizzle(const gl::Context *context,
{
const LevelInfoGL &levelInfo = getBaseLevelInfo();
GLenum resultSwizzle = value;
if (levelInfo.lumaWorkaround.enabled || levelInfo.depthStencilWorkaround)
if (levelInfo.lumaWorkaround.enabled)
{
if (levelInfo.lumaWorkaround.enabled)
switch (value)
{
switch (value)
{
case GL_RED:
case GL_GREEN:
case GL_BLUE:
if (levelInfo.sourceFormat == GL_LUMINANCE ||
levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
{
// Texture is backed by a RED or RG texture, point all color channels at the
// red channel.
ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
resultSwizzle = GL_RED;
}
else
{
ASSERT(levelInfo.sourceFormat == GL_ALPHA);
// Color channels are not supposed to exist, make them always sample 0.
resultSwizzle = GL_ZERO;
}
break;
case GL_RED:
case GL_GREEN:
case GL_BLUE:
if (levelInfo.sourceFormat == GL_LUMINANCE ||
levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
{
// Texture is backed by a RED or RG texture, point all color channels at the
// red channel.
ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
resultSwizzle = GL_RED;
}
else
{
ASSERT(levelInfo.sourceFormat == GL_ALPHA);
// Color channels are not supposed to exist, make them always sample 0.
resultSwizzle = GL_ZERO;
}
break;
case GL_ALPHA:
if (levelInfo.sourceFormat == GL_LUMINANCE)
{
// Alpha channel is not supposed to exist, make it always sample 1.
resultSwizzle = GL_ONE;
}
else if (levelInfo.sourceFormat == GL_ALPHA)
{
// Texture is backed by a RED texture, point the alpha channel at the red
// channel.
ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
resultSwizzle = GL_RED;
}
else
{
ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
// Texture is backed by an RG texture, point the alpha channel at the green
// channel.
ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
resultSwizzle = GL_GREEN;
}
break;
case GL_ZERO:
case GL_ONE:
// Don't modify the swizzle state when requesting ZERO or ONE.
resultSwizzle = value;
break;
default:
UNREACHABLE();
break;
}
}
else
{
ASSERT(levelInfo.depthStencilWorkaround);
switch (value)
{
case GL_RED:
// Don't modify the swizzle state when requesting the red channel.
resultSwizzle = value;
break;
case GL_GREEN:
case GL_BLUE:
if (context->getClientMajorVersion() <= 2)
{
// In OES_depth_texture/ARB_depth_texture, depth
// textures are treated as luminance.
resultSwizzle = GL_RED;
}
else
{
// In GLES 3.0, depth textures are treated as RED
// textures, so green and blue should be 0.
resultSwizzle = GL_ZERO;
}
break;
case GL_ALPHA:
// Depth textures should sample 1 from the alpha channel.
case GL_ALPHA:
if (levelInfo.sourceFormat == GL_LUMINANCE)
{
// Alpha channel is not supposed to exist, make it always sample 1.
resultSwizzle = GL_ONE;
break;
}
else if (levelInfo.sourceFormat == GL_ALPHA)
{
// Texture is backed by a RED texture, point the alpha channel at the red
// channel.
ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
resultSwizzle = GL_RED;
}
else
{
ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
// Texture is backed by an RG texture, point the alpha channel at the green
// channel.
ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
resultSwizzle = GL_GREEN;
}
break;
case GL_ZERO:
case GL_ONE:
// Don't modify the swizzle state when requesting ZERO or ONE.
resultSwizzle = value;
break;
case GL_ZERO:
case GL_ONE:
// Don't modify the swizzle state when requesting ZERO or ONE.
resultSwizzle = value;
break;
default:
UNREACHABLE();
break;
}
default:
UNREACHABLE();
break;
}
}
else if (levelInfo.depthStencilWorkaround)
{
switch (value)
{
case GL_RED:
// Don't modify the swizzle state when requesting the red channel.
resultSwizzle = value;
break;
case GL_GREEN:
case GL_BLUE:
if (context->getClientMajorVersion() <= 2)
{
// In OES_depth_texture/ARB_depth_texture, depth
// textures are treated as luminance.
resultSwizzle = GL_RED;
}
else
{
// In GLES 3.0, depth textures are treated as RED
// textures, so green and blue should be 0.
resultSwizzle = GL_ZERO;
}
break;
case GL_ALPHA:
// Depth textures should sample 1 from the alpha channel.
resultSwizzle = GL_ONE;
break;
case GL_ZERO:
case GL_ONE:
// Don't modify the swizzle state when requesting ZERO or ONE.
resultSwizzle = value;
break;
default:
UNREACHABLE();
break;
}
}
else if (levelInfo.emulatedAlphaChannel)
{
if (value == GL_ALPHA)
{
resultSwizzle = GL_ONE;
}
}

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

@ -47,11 +47,16 @@ struct LevelInfoGL
// Information about luminance alpha texture workarounds in the core profile.
LUMAWorkaroundGL lumaWorkaround;
// If this texture level hides the fact that it has an alpha channel by setting the sampler
// parameters to always sample 1.0.
bool emulatedAlphaChannel;
LevelInfoGL();
LevelInfoGL(GLenum sourceFormat,
GLenum nativeInternalFormat,
bool depthStencilWorkaround,
const LUMAWorkaroundGL &lumaWorkaround);
const LUMAWorkaroundGL &lumaWorkaround,
bool emulatedAlphaChannel);
};
class TextureGL : public TextureImpl
@ -199,6 +204,7 @@ class TextureGL : public TextureImpl
void setSwizzle(const gl::Context *context, GLint swizzle[4]);
GLenum getNativeInternalFormat(const gl::ImageIndex &index) const;
bool hasEmulatedAlphaChannel(const gl::ImageIndex &index) const;
private:
void setImageHelper(const gl::Context *context,

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

@ -64,13 +64,19 @@ class IOSurfaceSurfaceCGL : public SurfaceGL
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override;
bool hasEmulatedAlphaChannel() const override;
private:
angle::Result initializeAlphaChannel(const gl::Context *context, GLuint texture);
CGLContextObj mCGLContext;
IOSurfaceRef mIOSurface;
int mWidth;
int mHeight;
int mPlane;
int mFormatIndex;
bool mAlphaInitialized;
};
} // namespace rx

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

@ -9,11 +9,13 @@
#include "libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h"
#import <Cocoa/Cocoa.h>
#include <IOSurface/IOSurface.h>
#include <OpenGL/CGLIOSurface.h>
#include "common/debug.h"
#include "libANGLE/AttributeMap.h"
#include "libANGLE/renderer/gl/BlitGL.h"
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
@ -44,6 +46,7 @@ static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
{GL_RED, GL_UNSIGNED_BYTE, 1, GL_RED, GL_RED, GL_UNSIGNED_BYTE },
{GL_R16UI, GL_UNSIGNED_SHORT, 2, GL_RED, GL_RED, GL_UNSIGNED_SHORT },
{GL_RG, GL_UNSIGNED_BYTE, 2, GL_RG, GL_RG, GL_UNSIGNED_BYTE },
{GL_RGB, GL_UNSIGNED_BYTE, 4, GL_BGRA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, GL_BGRA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
{GL_RGBA, GL_HALF_FLOAT, 8, GL_RGBA, GL_RGBA, GL_HALF_FLOAT },
};
@ -74,7 +77,8 @@ IOSurfaceSurfaceCGL::IOSurfaceSurfaceCGL(const egl::SurfaceState &state,
mWidth(0),
mHeight(0),
mPlane(0),
mFormatIndex(-1)
mFormatIndex(-1),
mAlphaInitialized(false)
{
// Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
@ -89,6 +93,8 @@ IOSurfaceSurfaceCGL::IOSurfaceSurfaceCGL(const egl::SurfaceState &state,
EGLAttrib type = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
mFormatIndex = FindIOSurfaceFormatIndex(internalFormat, type);
ASSERT(mFormatIndex >= 0);
mAlphaInitialized = !hasEmulatedAlphaChannel();
}
IOSurfaceSurfaceCGL::~IOSurfaceSurfaceCGL()
@ -148,13 +154,18 @@ egl::Error IOSurfaceSurfaceCGL::bindTexImage(const gl::Context *context,
stateManager->bindTexture(gl::TextureType::Rectangle, textureID);
const auto &format = kIOSurfaceFormats[mFormatIndex];
auto error = CGLTexImageIOSurface2D(mCGLContext, GL_TEXTURE_RECTANGLE, format.nativeFormat,
mWidth, mHeight, format.nativeInternalFormat,
format.nativeType, mIOSurface, mPlane);
CGLError error = CGLTexImageIOSurface2D(mCGLContext, GL_TEXTURE_RECTANGLE, format.nativeFormat,
mWidth, mHeight, format.nativeInternalFormat,
format.nativeType, mIOSurface, mPlane);
if (error != kCGLNoError)
{
return egl::EglContextLost();
return egl::EglContextLost() << "CGLTexImageIOSurface2D failed: " << CGLErrorString(error);
}
if (IsError(initializeAlphaChannel(context, textureID)))
{
return egl::EglContextLost() << "Failed to initialize IOSurface alpha channel.";
}
return egl::NoError();
@ -247,8 +258,9 @@ class IOSurfaceFramebuffer : public FramebufferGL
IOSurfaceFramebuffer(const gl::FramebufferState &data,
GLuint id,
GLuint textureId,
bool isDefault)
: FramebufferGL(data, id, isDefault), mTextureId(textureId)
bool isDefault,
bool emulatedAlpha)
: FramebufferGL(data, id, isDefault, emulatedAlpha), mTextureId(textureId)
{}
void destroy(const gl::Context *context) override
{
@ -273,8 +285,17 @@ FramebufferImpl *IOSurfaceSurfaceCGL::createDefaultFramebuffer(const gl::Context
CGLError error = CGLTexImageIOSurface2D(mCGLContext, GL_TEXTURE_RECTANGLE, format.nativeFormat,
mWidth, mHeight, format.nativeInternalFormat,
format.nativeType, mIOSurface, mPlane);
if (error != kCGLNoError)
{
ERR() << "CGLTexImageIOSurface2D failed: " << CGLErrorString(error);
}
ASSERT(error == kCGLNoError);
if (IsError(initializeAlphaChannel(context, texture)))
{
ERR() << "Failed to initialize IOSurface alpha channel.";
}
GLuint framebuffer = 0;
functions->genFramebuffers(1, &framebuffer);
stateManager->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
@ -282,7 +303,27 @@ FramebufferImpl *IOSurfaceSurfaceCGL::createDefaultFramebuffer(const gl::Context
functions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE,
texture, 0);
return new IOSurfaceFramebuffer(state, framebuffer, texture, true);
return new IOSurfaceFramebuffer(state, framebuffer, texture, true, hasEmulatedAlphaChannel());
}
angle::Result IOSurfaceSurfaceCGL::initializeAlphaChannel(const gl::Context *context,
GLuint texture)
{
if (mAlphaInitialized)
{
return angle::Result::Continue;
}
BlitGL *blitter = GetBlitGL(context);
ANGLE_TRY(blitter->clearRenderableTextureAlphaToOne(texture, gl::TextureTarget::Rectangle, 0));
mAlphaInitialized = true;
return angle::Result::Continue;
}
bool IOSurfaceSurfaceCGL::hasEmulatedAlphaChannel() const
{
const auto &format = kIOSurfaceFormats[mFormatIndex];
return format.internalFormat == GL_RGB;
}
} // namespace rx

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

@ -137,7 +137,7 @@ FramebufferImpl *PbufferSurfaceCGL::createDefaultFramebuffer(const gl::Context *
functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mDSRenderbuffer);
return new FramebufferGL(state, framebuffer, true);
return new FramebufferGL(state, framebuffer, true, false);
}
} // namespace rx

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

@ -331,7 +331,7 @@ FramebufferImpl *WindowSurfaceCGL::createDefaultFramebuffer(const gl::Context *c
functions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
mDSRenderbuffer);
return new FramebufferGL(state, framebuffer, true);
return new FramebufferGL(state, framebuffer, true, false);
}
} // namespace rx

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

@ -317,7 +317,7 @@ GLuint DisplayOzone::Buffer::createGLFB(const gl::Context *context)
FramebufferGL *DisplayOzone::Buffer::framebufferGL(const gl::Context *context,
const gl::FramebufferState &state)
{
return new FramebufferGL(state, createGLFB(context), true);
return new FramebufferGL(state, createGLFB(context), true, false);
}
void DisplayOzone::Buffer::present(const gl::Context *context)

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

@ -498,7 +498,7 @@ FramebufferImpl *D3DTextureSurfaceWGL::createDefaultFramebuffer(const gl::Contex
mDepthStencilRenderbufferID);
}
return new FramebufferGL(data, framebufferID, true);
return new FramebufferGL(data, framebufferID, true, false);
}
HDC D3DTextureSurfaceWGL::getDC() const

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

@ -296,7 +296,7 @@ FramebufferImpl *DXGISwapChainWindowSurfaceWGL::createDefaultFramebuffer(
}
}
return new FramebufferGL(data, framebufferID, true);
return new FramebufferGL(data, framebufferID, true, false);
}
HDC DXGISwapChainWindowSurfaceWGL::getDC() const

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

@ -331,6 +331,24 @@ TEST_P(IOSurfaceClientBufferTest, ReadFromBGRA8888IOSurface)
doSampleTest(ioSurface, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B | A);
}
// Test using BGRX8888 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToBGRX8888IOSurface)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
GLColor color(3, 2, 1, 255);
doClearTest(ioSurface, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color));
}
// Test reading from BGRX8888 IOSurfaces
TEST_P(IOSurfaceClientBufferTest, ReadFromBGRX8888IOSurface)
{
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, 'BGRA', 4);
GLColor color(3, 2, 1, 4);
doSampleTest(ioSurface, GL_RGB, GL_UNSIGNED_BYTE, &color, sizeof(color), R | G | B);
}
// Test using RG88 IOSurfaces for rendering
TEST_P(IOSurfaceClientBufferTest, RenderToRG88IOSurface)
{