Commit 9db70de8 by Corentin Wallez Committed by Commit Bot

Reland: Implement EGL_ANGLE_iosurface_client_buffer

Includes a fix for creating pbuffers with <buftype> EGL_D3D_TEXTURE with EGL_WIDTH and EGL_HEIGHT attributes. BUG=angleproject:1649 TBR=geofflang@chromium.org Change-Id: Id2974b8fab02c3218febfac708b9b034e65cbc53 Reviewed-on: https://chromium-review.googlesource.com/823248Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent 3acfc625
......@@ -73,31 +73,30 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
"When <buftype> is EGL_IOSURFACE_ANGLE, <attrib_list> must contain all the
following attributes under the following constraints otherwise
EGL_BAD_PARAMETER is generated:
- EGL_TEXTURE_FORMAT, EGL_TEXTURE_TYPE_ANGLE, and
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE followed by OpenGL enums for texture
formats, texture types, and texture internal format respectively.
- EGL_TEXTURE_TYPE_ANGLE, and EGL_TEXTURE_INTERNAL_FORMAT_ANGLE followed
by OpenGL enums for texture types, and texture internal format
respectively.
- EGL_TEXTURE_FORMAT with a value of EGL_TEXTURE_RGBA
- EGL_WIDTH with a value between 1 and the width of <buffer>.
- EGL_HEIGHT with a value between 1 and the width of <buffer>.
- EGL_TEXTURE_TARGET with a value of EGL_TEXTURE_RECTANGLE_ANGLE
- EGL_IOSURFACE_PLANE_ANGLE with a value between 0 and the number of
planes of <buffer> (exclusive).
In addition the EGL_TEXTURE_FORMAT, EGL_TEXTURE_TYPE_ANGLE and
In addition the EGL_TEXTURE_TYPE_ANGLE and
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE attributes must be one of the
combinations listed in table egl.iosurface.formats or an
EGL_BAD_PARAMETER is generated. The combination must also be a valid
combinations for glTexImage2D or EGL_BAD_PARAMETER is generated."
---------------------------------------------------------------------------
Texture Format Texture Type Texture Internal Format
Texture Type Texture Internal Format
---------------------------------------------------------------------------
GL_RED GL_UNSIGNED_BYTE GL_RED
GL_RED GL_UNSIGNED_SHORT GL_R16UI
GL_RG GL_UNSIGNED_BYTE GL_RG
GL_BGRA GL_UNSIGNED_INT_8_8_8_8_REV GL_RGBA
GL_BGRA GL_UNSIGNED_INT_8_8_8_8_REV GL_RGBA
GL_BGRA GL_UNSIGNED_INT_8_8_8_8_REV GL_RGBA
GL_RGBA GL_HALF_FLOAT GL_RGBA
GL_UNSIGNED_BYTE GL_RED
GL_UNSIGNED_SHORT GL_RED_INTEGER
GL_UNSIGNED_BYTE GL_RG
GL_UNSIGNED_BYTE GL_BGRA_EXT
GL_HALF_FLOAT GL_RGBA
---------------------------------------------------------------------------
Table egl.iosurface.formats - Valid combinations of format, type and
internal format for IOSurface-backed pbuffers.
......
......@@ -165,6 +165,15 @@ EGLAPI EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limi
#endif
#endif /* EGL_ANGLE_program_cache_control */
#ifndef EGL_ANGLE_iosurface_client_buffer
#define EGL_ANGLE_iosurface_client_buffer 1
#define EGL_IOSURFACE_ANGLE 0x3454
#define EGL_IOSURFACE_PLANE_ANGLE 0x345A
#define EGL_TEXTURE_RECTANGLE_ANGLE 0x345B
#define EGL_TEXTURE_TYPE_ANGLE 0x345C
#define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
#endif /* EGL_ANGLE_iosurface_client_buffer */
// clang-format on
#endif // INCLUDE_EGL_EGLEXT_ANGLE_
......@@ -993,6 +993,22 @@ GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget)
}
}
GLenum EGLTextureTargetToGLTextureTarget(EGLenum eglTarget)
{
switch (eglTarget)
{
case EGL_TEXTURE_2D:
return GL_TEXTURE_2D;
case EGL_TEXTURE_RECTANGLE_ANGLE:
return GL_TEXTURE_RECTANGLE_ANGLE;
default:
UNREACHABLE();
return GL_NONE;
}
}
GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer)
{
return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
......
......@@ -153,6 +153,7 @@ namespace egl_gl
{
GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget);
GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget);
GLenum EGLTextureTargetToGLTextureTarget(EGLenum eglTarget);
GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer);
}
......
......@@ -1151,7 +1151,8 @@ DisplayExtensions::DisplayExtensions()
displayTextureShareGroup(false),
createContextClientArrays(false),
programCacheControl(false),
robustResourceInitialization(false)
robustResourceInitialization(false),
iosurfaceClientBuffer(false)
{
}
......@@ -1196,6 +1197,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_ANGLE_create_context_client_arrays", createContextClientArrays, &extensionStrings);
InsertExtensionString("EGL_ANGLE_program_cache_control", programCacheControl, &extensionStrings);
InsertExtensionString("EGL_ANGLE_robust_resource_initialization", robustResourceInitialization, &extensionStrings);
InsertExtensionString("EGL_ANGLE_iosurface_client_buffer", iosurfaceClientBuffer, &extensionStrings);
// TODO(jmadill): Enable this when complete.
//InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings);
// clang-format on
......
......@@ -710,6 +710,9 @@ struct DisplayExtensions
// EGL_ANGLE_robust_resource_initialization
bool robustResourceInitialization;
// EGL_ANGLE_iosurface_client_buffer
bool iosurfaceClientBuffer;
};
struct DeviceExtensions
......
......@@ -12,8 +12,6 @@
#include <EGL/eglext.h>
#include <iostream>
#include "libANGLE/Config.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
......@@ -59,7 +57,7 @@ Surface::Surface(EGLint surfaceType, const egl::Config *config, const AttributeM
mSwapBehavior(EGL_NONE),
mOrientation(0),
mTexture(),
mBackFormat(config->renderTargetFormat),
mColorFormat(config->renderTargetFormat),
mDSFormat(config->depthStencilFormat)
{
mPostSubBufferRequested = (attributes.get(EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE) == EGL_TRUE);
......@@ -387,7 +385,7 @@ gl::Extents Surface::getAttachmentSize(const gl::ImageIndex & /*target*/) const
const gl::Format &Surface::getAttachmentFormat(GLenum binding, const gl::ImageIndex &target) const
{
return (binding == GL_BACK ? mBackFormat : mDSFormat);
return (binding == GL_BACK ? mColorFormat : mDSFormat);
}
GLsizei Surface::getAttachmentSamples(const gl::ImageIndex &target) const
......@@ -447,6 +445,13 @@ PbufferSurface::PbufferSurface(rx::EGLImplFactory *implFactory,
{
mImplementation =
implFactory->createPbufferFromClientBuffer(mState, buftype, clientBuffer, attribs);
if (buftype == EGL_IOSURFACE_ANGLE)
{
GLenum internalFormat = static_cast<GLenum>(attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE));
GLenum type = static_cast<GLenum>(attribs.get(EGL_TEXTURE_TYPE_ANGLE));
mColorFormat = gl::Format(internalFormat, type);
}
}
PbufferSurface::~PbufferSurface()
......
......@@ -125,6 +125,8 @@ class Surface : public gl::FramebufferAttachmentObject
bool isRobustResourceInitEnabled() const { return mRobustResourceInitialization; }
const gl::Format &getBindTexImageFormat() const { return mColorFormat; }
protected:
Surface(EGLint surfaceType, const egl::Config *config, const AttributeMap &attributes);
~Surface() override;
......@@ -175,7 +177,7 @@ class Surface : public gl::FramebufferAttachmentObject
gl::BindingPointer<gl::Texture> mTexture;
gl::Format mBackFormat;
gl::Format mColorFormat;
gl::Format mDSFormat;
private:
......
......@@ -1235,7 +1235,7 @@ Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *sur
// Set the image info to the size and format of the surface
ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE);
Extents size(surface->getWidth(), surface->getHeight(), 1);
ImageDesc desc(size, Format(surface->getConfig()->renderTargetFormat), InitState::Initialized);
ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
mState.setImageDesc(mState.mTarget, 0, desc);
signalDirty(InitState::Initialized);
return NoError();
......
......@@ -45,6 +45,10 @@ class DisplayCGL : public DisplayGL
egl::Error restoreLostDevice(const egl::Display *display) override;
bool isValidNativeWindow(EGLNativeWindowType window) const override;
egl::Error validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override;
egl::Error getDevice(DeviceImpl **device) override;
......@@ -53,6 +57,8 @@ class DisplayCGL : public DisplayGL
egl::Error waitClient(const gl::Context *context) const override;
egl::Error waitNative(const gl::Context *context, EGLint engine) const override;
CGLContextObj getCGLContext() const;
private:
const FunctionsGL *getFunctionsGL() const override;
egl::Error makeCurrentSurfaceless(gl::Context *context) override;
......
......@@ -14,6 +14,7 @@
#include "common/debug.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h"
#include "libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h"
#include "libANGLE/renderer/gl/cgl/WindowSurfaceCGL.h"
......@@ -131,8 +132,9 @@ SurfaceImpl *DisplayCGL::createPbufferFromClientBuffer(const egl::SurfaceState &
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return nullptr;
ASSERT(buftype == EGL_IOSURFACE_ANGLE);
return new IOSurfaceSurfaceCGL(state, this->getRenderer(), this, clientBuffer, attribs);
}
SurfaceImpl *DisplayCGL::createPixmapSurface(const egl::SurfaceState &state,
......@@ -233,12 +235,32 @@ bool DisplayCGL::isValidNativeWindow(EGLNativeWindowType window) const
return [layer isKindOfClass:[CALayer class]];
}
egl::Error DisplayCGL::validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
ASSERT(buftype == EGL_IOSURFACE_ANGLE);
if (!IOSurfaceSurfaceCGL::validateAttributes(clientBuffer, attribs))
{
return egl::EglBadAttribute();
}
return egl::NoError();
}
std::string DisplayCGL::getVendorString() const
{
// TODO(cwallez) find a useful vendor string
return "";
}
CGLContextObj DisplayCGL::getCGLContext() const
{
return mContext;
}
const FunctionsGL *DisplayCGL::getFunctionsGL() const
{
return mFunctions;
......@@ -246,6 +268,7 @@ const FunctionsGL *DisplayCGL::getFunctionsGL() const
void DisplayCGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->iosurfaceClientBuffer = true;
outExtensions->surfacelessContext = true;
// Contexts are virtualized so textures can be shared globally
......
//
// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// PBufferSurfaceCGL.h: an implementation of PBuffers created from IOSurfaces using
// EGL_ANGLE_iosurface_client_buffer
#ifndef LIBANGLE_RENDERER_GL_CGL_IOSURFACESURFACECGL_H_
#define LIBANGLE_RENDERER_GL_CGL_IOSURFACESURFACECGL_H_
#include "libANGLE/renderer/gl/SurfaceGL.h"
struct __IOSurface;
typedef __IOSurface *IOSurfaceRef;
namespace egl
{
class AttributeMap;
} // namespace gl
namespace rx
{
class DisplayCGL;
class FunctionsGL;
class StateManagerGL;
class IOSurfaceSurfaceCGL : public SurfaceGL
{
public:
IOSurfaceSurfaceCGL(const egl::SurfaceState &state,
RendererGL *renderer,
DisplayCGL *display,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs);
~IOSurfaceSurfaceCGL() override;
egl::Error initialize(const egl::Display *display) override;
egl::Error makeCurrent() override;
egl::Error swap(const gl::Context *context) override;
egl::Error postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
egl::Error bindTexImage(gl::Texture *texture, EGLint buffer) override;
egl::Error releaseTexImage(EGLint buffer) override;
void setSwapInterval(EGLint interval) override;
EGLint getWidth() const override;
EGLint getHeight() const override;
EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override;
static bool validateAttributes(EGLClientBuffer buffer, const egl::AttributeMap &attribs);
private:
DisplayCGL *mDisplay;
RendererGL *mRenderer;
StateManagerGL *mStateManager;
IOSurfaceRef mIOSurface;
int mWidth;
int mHeight;
int mPlane;
int mFormatIndex;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_GL_CGL_IOSURFACESURFACECGL_H_
//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// PBufferSurfaceCGL.cpp: an implementation of PBuffers created from IOSurfaces using
// EGL_ANGLE_iosurface_client_buffer
#include "libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h"
#include <IOSurface/IOSurface.h>
#include <OpenGL/CGLIOSurface.h>
#include "common/debug.h"
#include "libANGLE/AttributeMap.h"
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/TextureGL.h"
#include "libANGLE/renderer/gl/cgl/DisplayCGL.h"
namespace rx
{
namespace
{
struct IOSurfaceFormatInfo
{
GLenum internalFormat;
GLenum type;
size_t componentBytes;
GLenum nativeInternalFormat;
GLenum nativeFormat;
GLenum nativeType;
};
// clang-format off
static const IOSurfaceFormatInfo kIOSurfaceFormats[] = {
{GL_RED, GL_UNSIGNED_BYTE, 1, GL_RED, GL_RED, GL_UNSIGNED_BYTE },
{GL_R8UI, 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_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 },
};
// clang-format on
int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
{
for (int i = 0; i < static_cast<int>(ArraySize(kIOSurfaceFormats)); ++i)
{
const auto &formatInfo = kIOSurfaceFormats[i];
if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
{
return i;
}
}
return -1;
}
} // anonymous namespace
IOSurfaceSurfaceCGL::IOSurfaceSurfaceCGL(const egl::SurfaceState &state,
RendererGL *renderer,
DisplayCGL *display,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
: SurfaceGL(state, renderer),
mDisplay(display),
mRenderer(renderer),
mStateManager(renderer->getStateManager()),
mIOSurface(nullptr),
mWidth(0),
mHeight(0),
mPlane(0),
mFormatIndex(-1)
{
// Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
CFRetain(mIOSurface);
// Extract attribs useful for the call to CGLTexImageIOSurface2D
mWidth = attribs.get(EGL_WIDTH);
mHeight = attribs.get(EGL_HEIGHT);
mPlane = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
EGLAttrib type = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
mFormatIndex = FindIOSurfaceFormatIndex(internalFormat, type);
ASSERT(mFormatIndex >= 0);
}
IOSurfaceSurfaceCGL::~IOSurfaceSurfaceCGL()
{
if (mIOSurface != nullptr)
{
CFRelease(mIOSurface);
mIOSurface = nullptr;
}
}
egl::Error IOSurfaceSurfaceCGL::initialize(const egl::Display *display)
{
return egl::NoError();
}
egl::Error IOSurfaceSurfaceCGL::makeCurrent()
{
// Make current is not supported on IOSurface pbuffers.
return egl::EglBadSurface();
}
egl::Error IOSurfaceSurfaceCGL::swap(const gl::Context *context)
{
UNREACHABLE();
return egl::NoError();
}
egl::Error IOSurfaceSurfaceCGL::postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height)
{
UNREACHABLE();
return egl::NoError();
}
egl::Error IOSurfaceSurfaceCGL::querySurfacePointerANGLE(EGLint attribute, void **value)
{
UNREACHABLE();
return egl::NoError();
}
egl::Error IOSurfaceSurfaceCGL::bindTexImage(gl::Texture *texture, EGLint buffer)
{
const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
GLuint textureID = textureGL->getTextureID();
mStateManager->bindTexture(GL_TEXTURE_RECTANGLE, textureID);
const auto &format = kIOSurfaceFormats[mFormatIndex];
auto error = CGLTexImageIOSurface2D(
mDisplay->getCGLContext(), GL_TEXTURE_RECTANGLE, format.nativeFormat, mWidth, mHeight,
format.nativeInternalFormat, format.nativeType, mIOSurface, mPlane);
if (error != kCGLNoError)
{
return egl::EglContextLost();
}
return egl::NoError();
}
egl::Error IOSurfaceSurfaceCGL::releaseTexImage(EGLint buffer)
{
gl::Error error = mRenderer->flush();
if (error.isError())
{
return egl::EglContextLost();
}
return egl::NoError();
}
void IOSurfaceSurfaceCGL::setSwapInterval(EGLint interval)
{
UNREACHABLE();
}
EGLint IOSurfaceSurfaceCGL::getWidth() const
{
return mWidth;
}
EGLint IOSurfaceSurfaceCGL::getHeight() const
{
return mHeight;
}
EGLint IOSurfaceSurfaceCGL::isPostSubBufferSupported() const
{
UNREACHABLE();
return EGL_FALSE;
}
EGLint IOSurfaceSurfaceCGL::getSwapBehavior() const
{
// N/A because you can't MakeCurrent an IOSurface, return any valid value.
return EGL_BUFFER_PRESERVED;
}
// static
bool IOSurfaceSurfaceCGL::validateAttributes(EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
// The plane must exist for this IOSurface. IOSurfaceGetPlaneCount can return 0 for non-planar
// ioSurfaces but we will treat non-planar like it is a single plane.
size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
EGLAttrib plane = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
if (plane < 0 || static_cast<size_t>(plane) >= surfacePlaneCount)
{
return false;
}
// The width height specified must be at least (1, 1) and at most the plane size
EGLAttrib width = attribs.get(EGL_WIDTH);
EGLAttrib height = attribs.get(EGL_HEIGHT);
if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
height < 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
{
return false;
}
// Find this IOSurface format
EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
EGLAttrib type = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
int formatIndex = FindIOSurfaceFormatIndex(internalFormat, type);
if (formatIndex < 0)
{
return false;
}
// Check that the format matches this IOSurface plane
if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, plane) !=
kIOSurfaceFormats[formatIndex].componentBytes)
{
return false;
}
return true;
}
} // namespace rx
......@@ -1045,6 +1045,18 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
}
break;
case EGL_IOSURFACE_ANGLE:
if (!displayExtensions.iosurfaceClientBuffer)
{
return EglBadParameter() << "<buftype> EGL_IOSURFACE_ANGLE requires the "
"EGL_ANGLE_iosurface_client_buffer extension.";
}
if (buffer == nullptr)
{
return EglBadParameter() << "<buffer> must be non null";
}
break;
default:
return EglBadParameter();
}
......@@ -1056,55 +1068,87 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
switch (attribute)
{
case EGL_WIDTH:
case EGL_HEIGHT:
if (!displayExtensions.d3dShareHandleClientBuffer)
{
return EglBadParameter();
}
if (value < 0)
{
return EglBadParameter();
}
break;
case EGL_WIDTH:
case EGL_HEIGHT:
if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE &&
buftype != EGL_D3D_TEXTURE_ANGLE &&
buftype != EGL_IOSURFACE_ANGLE)
{
return EglBadParameter()
<< "Width and Height are not supported for thie <buftype>";
}
if (value < 0)
{
return EglBadParameter() << "Width and Height must be positive";
}
break;
case EGL_TEXTURE_FORMAT:
switch (value)
{
case EGL_NO_TEXTURE:
case EGL_TEXTURE_RGB:
case EGL_TEXTURE_RGBA:
case EGL_TEXTURE_FORMAT:
switch (value)
{
case EGL_NO_TEXTURE:
case EGL_TEXTURE_RGB:
case EGL_TEXTURE_RGBA:
break;
default:
return EglBadAttribute() << "Invalid value for EGL_TEXTURE_FORMAT";
}
break;
default:
return EglBadAttribute();
}
break;
case EGL_TEXTURE_TARGET:
switch (value)
{
case EGL_NO_TEXTURE:
case EGL_TEXTURE_2D:
case EGL_TEXTURE_TARGET:
switch (value)
{
case EGL_NO_TEXTURE:
case EGL_TEXTURE_2D:
break;
case EGL_TEXTURE_RECTANGLE_ANGLE:
if (buftype != EGL_IOSURFACE_ANGLE)
{
return EglBadParameter()
<< "<buftype> doesn't support rectangle texture targets";
}
break;
default:
return EglBadAttribute() << "Invalid value for EGL_TEXTURE_TARGET";
}
break;
default:
return EglBadAttribute();
}
break;
case EGL_MIPMAP_TEXTURE:
break;
case EGL_MIPMAP_TEXTURE:
break;
case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
if (!displayExtensions.flexibleSurfaceCompatibility)
{
return EglBadAttribute()
<< "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used "
"without EGL_ANGLE_flexible_surface_compatibility support.";
}
break;
case EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE:
if (!displayExtensions.flexibleSurfaceCompatibility)
{
return EglBadAttribute()
<< "EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE cannot be used "
"without EGL_ANGLE_flexible_surface_compatibility support.";
}
break;
default:
return EglBadAttribute();
case EGL_IOSURFACE_PLANE_ANGLE:
if (buftype != EGL_IOSURFACE_ANGLE)
{
return EglBadAttribute() << "<buftype> doesn't support iosurface plane";
}
break;
case EGL_TEXTURE_TYPE_ANGLE:
if (buftype != EGL_IOSURFACE_ANGLE)
{
return EglBadAttribute() << "<buftype> doesn't support texture type";
}
break;
case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
if (buftype != EGL_IOSURFACE_ANGLE)
{
return EglBadAttribute() << "<buftype> doesn't support texture internal format";
}
break;
default:
return EglBadAttribute();
}
}
......@@ -1120,11 +1164,20 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
{
return EglBadMatch();
}
if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) ||
if ((textureFormat == EGL_TEXTURE_RGB && config->bindToTextureRGB != EGL_TRUE) ||
(textureFormat == EGL_TEXTURE_RGBA && config->bindToTextureRGBA != EGL_TRUE))
{
return EglBadAttribute();
// TODO(cwallez@chromium.org): For IOSurface pbuffers we require that EGL_TEXTURE_RGBA is
// set so that eglBinTexImage works. Normally this is only allowed if the config exposes the
// bindToTextureRGB/RGBA flag. This issue is that enabling this flags means that
// eglBindTexImage should also work for regular pbuffers which isn't implemented on macOS.
// Instead of adding the flag we special case the check here to be ignored for IOSurfaces.
// The TODO is to find a proper solution for this, maybe by implementing eglBindTexImage on
// OSX?
if (buftype != EGL_IOSURFACE_ANGLE)
{
return EglBadAttribute();
}
}
if (buftype == EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE)
......@@ -1144,6 +1197,28 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display, EGLenum buftype, E
}
}
if (buftype == EGL_IOSURFACE_ANGLE)
{
if (textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE)
{
return EglBadAttribute() << "EGL_IOSURFACE requires the EGL_TEXTURE_RECTANGLE target";
}
if (textureFormat != EGL_TEXTURE_RGBA)
{
return EglBadAttribute() << "EGL_IOSURFACE requires the EGL_TEXTURE_RGBA format";
}
if (!attributes.contains(EGL_WIDTH) || !attributes.contains(EGL_HEIGHT) ||
!attributes.contains(EGL_TEXTURE_FORMAT) ||
!attributes.contains(EGL_TEXTURE_TYPE_ANGLE) ||
!attributes.contains(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE) ||
!attributes.contains(EGL_IOSURFACE_PLANE_ANGLE))
{
return EglBadParameter() << "Missing required attribute for EGL_IOSURFACE";
}
}
ANGLE_TRY(display->validateClientBuffer(config, buftype, buffer, attributes));
return NoError();
......
......@@ -696,6 +696,8 @@
[
'libANGLE/renderer/gl/cgl/DisplayCGL.mm',
'libANGLE/renderer/gl/cgl/DisplayCGL.h',
'libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.mm',
'libANGLE/renderer/gl/cgl/IOSurfaceSurfaceCGL.h',
'libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.mm',
'libANGLE/renderer/gl/cgl/PbufferSurfaceCGL.h',
'libANGLE/renderer/gl/cgl/WindowSurfaceCGL.mm',
......
......@@ -9,6 +9,7 @@
#include "libGLESv2/entry_points_egl.h"
#include "common/debug.h"
#include "common/utilities.h"
#include "common/version.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
......@@ -760,7 +761,8 @@ EGLBoolean EGLAPIENTRY BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint b
gl::Context *context = thread->getContext();
if (context)
{
gl::Texture *textureObject = context->getTargetTexture(GL_TEXTURE_2D);
GLenum target = egl_gl::EGLTextureTargetToGLTextureTarget(eglSurface->getTextureTarget());
gl::Texture *textureObject = context->getTargetTexture(target);
ASSERT(textureObject != nullptr);
if (textureObject->getImmutableFormat())
......
......@@ -129,7 +129,17 @@ if (is_win || is_linux || is_mac || is_android) {
sources =
rebase_path(end2end_gypi.angle_end2end_tests_sources, ".", "../..")
libs = []
if (is_mac) {
sources += rebase_path(end2end_gypi.angle_end2end_tests_mac_sources,
".",
"../..")
libs += [
"CoreFoundation.framework",
"IOSurface.framework",
]
}
if (is_win) {
sources += rebase_path(end2end_gypi.angle_end2end_tests_win_sources,
".",
......
......@@ -114,6 +114,10 @@
'<(angle_path)/src/tests/test_utils/angle_test_instantiate.h',
'<(angle_path)/src/tests/test_utils/gl_raii.h',
],
'angle_end2end_tests_mac_sources':
[
'<(angle_path)/src/tests/egl_tests/EGLIOSurfaceClientBufferTest.cpp',
],
'angle_end2end_tests_win_sources':
[
'<(angle_path)/src/tests/gl_tests/D3DImageFormatConversionTest.cpp',
......@@ -153,6 +157,21 @@
],
'conditions':
[
['OS=="mac"',
{
'sources':
[
'<@(angle_end2end_tests_mac_sources)',
],
'link_settings':
{
'libraries':
[
'$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
'$(SDKROOT)/System/Library/Frameworks/IOSurface.framework',
],
},
}],
['OS=="win"',
{
'sources':
......
//
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLIOSurfaceClientBufferTest.cpp: tests for the EGL_ANGLE_iosurface_client_buffer extension.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/gl_raii.h"
#include <CoreFoundation/CoreFoundation.h>
#include <IOSurface/IOSurface.h>
#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
using namespace angle;
namespace
{
void AddIntegerValue(CFMutableDictionaryRef dictionary, const CFStringRef key, int32_t value)
{
CFNumberRef number = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value);
CFDictionaryAddValue(dictionary, key, number);
CFRelease(number);
}
} // anonymous namespace
class IOSurfaceClientBufferTest : public ANGLETest
{
protected:
IOSurfaceClientBufferTest() : mConfig(0), mDisplay(nullptr) {}
void SetUp() override
{
ANGLETest::SetUp();
mConfig = getEGLWindow()->getConfig();
mDisplay = getEGLWindow()->getDisplay();
}
void TearDown() override { ANGLETest::TearDown(); }
EGLConfig mConfig;
EGLDisplay mDisplay;
};
TEST_P(IOSurfaceClientBufferTest, RenderToBGRA8888IOSurface)
{
// Create a 1 by 1 BGRA8888 IOSurface
IOSurfaceRef ioSurface = nullptr;
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
AddIntegerValue(dict, kIOSurfaceWidth, 1);
AddIntegerValue(dict, kIOSurfaceHeight, 1);
AddIntegerValue(dict, kIOSurfacePixelFormat, 'BGRA');
AddIntegerValue(dict, kIOSurfaceBytesPerElement, 4);
ioSurface = IOSurfaceCreate(dict);
CFRelease(dict);
EXPECT_NE(nullptr, ioSurface);
// Make a PBuffer from it using the EGL_ANGLE_iosurface_client_buffer extension
// clang-format off
const EGLint attribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_IOSURFACE_PLANE_ANGLE, 0,
EGL_TEXTURE_TARGET, EGL_TEXTURE_RECTANGLE_ANGLE,
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_BGRA_EXT,
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
EGL_TEXTURE_TYPE_ANGLE, GL_UNSIGNED_BYTE,
EGL_NONE, EGL_NONE,
};
// clang-format off
EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(mDisplay, EGL_IOSURFACE_ANGLE, ioSurface, mConfig, attribs);
EXPECT_NE(EGL_NO_SURFACE, pbuffer);
// Bind and glClear the pbuffer
GLTexture tex;
glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex);
EGLBoolean result = eglBindTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
EXPECT_GL_NO_ERROR();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ANGLE, tex, 0);
EXPECT_GL_NO_ERROR();
EXPECT_GLENUM_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), GL_FRAMEBUFFER_COMPLETE);
EXPECT_GL_NO_ERROR();
glClearColor(0, 1, 0, 1);
EXPECT_GL_NO_ERROR();
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR();
// Unbind pbuffer and check content.
result = eglReleaseTexImage(mDisplay, pbuffer, EGL_BACK_BUFFER);
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
IOSurfaceLock(ioSurface, kIOSurfaceLockReadOnly, nullptr);
GLColor color = *reinterpret_cast<const GLColor*>(IOSurfaceGetBaseAddress(ioSurface));
IOSurfaceUnlock(ioSurface, kIOSurfaceLockReadOnly, nullptr);
CFRelease(ioSurface);
EXPECT_EQ(color, GLColor::green);
}
ANGLE_INSTANTIATE_TEST(IOSurfaceClientBufferTest, ES3_OPENGL());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment