Commit c80eada5 by Alexis Hetu Committed by Alexis Hétu

eglCreatePbufferFromClientBuffer implementation

Added support for eglCreatePbufferFromClientBuffer(), using an IOSurface on MacOS, or just a straight buffer pointer on other platforms. Added new unit tests (IOSurfaceClientBufferTest class), which pass on both Windows and MacOS. Change-Id: I79a6b420d85fb1f3ae505e0c0067bad2e27510d4 Reviewed-on: https://swiftshader-review.googlesource.com/17168Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 858c0393
Name
ANGLE_iosurface_client_buffer
Name Strings
EGL_ANGLE_iosurface_client_buffer
Contributors
Corentin Wallez
Geoff Lang
Contacts
Corentin Wallez, Google Inc. (cwallez 'at' google.com)
Status
Draft
Version
Version 1, Dec 6, 2017
Number
EGL Extension #??
Dependencies
This extension is written against the wording of the EGL 1.4
Specification.
Overview
This extension allows creating EGL surfaces from IOSurface objects.
New Types
None
New Procedures and Functions
None
New Tokens
Accepted in the <buftype> parameter of eglCreatePbufferFromClientBuffer:
EGL_IOSURFACE_ANGLE 0x3454
EGL_IOSURFACE_PLANE_ANGLE 0x345A
EGL_TEXTURE_RECTANGLE_ANGLE 0x345B
EGL_TEXTURE_TYPE_ANGLE 0x345C
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
Replace the last sentence of paragraph 1 of Section 3.5.3 with the
following text.
"Currently, the only client API resources which may be bound in this
fashion are OpenVG VGImage objects and IOSurface objects."
Replace the third paragraph of Section 3.5.3 with the following text.
"<buftype> specifies the type of buffer to be bound. The only allowed values
of <buftype> are EGL_OPENVG_IMAGE and EGL_IOSURFACE_ANGLE".
Append the following text to the fourth paragraph of Section 3.5.3.
"When <buftype> is EGL_IOSURFACE_ANGLE, <buffer> must be a valid IOSurface
object case into the type EGLClientBuffer."
Append to the end of Section 3.5.3.
"When <buftype> is EGL_IOSURFACE_ANGLE, <attrib_list> must contain all the
following attributes otherwise EGL_BAD_PARAMETER is generated. The
attributes must satisfy the following constraints otherwise
EGL_BAD_ATTRIBUTE is generated:
- 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 height 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_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 Type Texture Internal Format
---------------------------------------------------------------------------
GL_UNSIGNED_BYTE GL_RED
GL_UNSIGNED_SHORT GL_R16UI
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.
---------------------------------------------------------------------------
Append to the end of Section 3.5.3.
"When a pbuffer is created with type EGL_IOSURFACE_ANGLE, the contents
of the associcated IOSurface object are undefined while the pbuffer is
bound to a client texture."
Append to the list of errors generated by eglMakeCurrent in Section 3.7.3:
" - If either draw or read are pbuffers created with
eglCreatePbufferFromClientBuffer with <buftype> set to EGL_IOSURFACE_ANGLE,
an EGL_BAD_SURFACE is generated."
Issues
There are no issues, please move on.
Revision History
Version 1, 2017/12/06 - first draft.
...@@ -24,6 +24,11 @@ ...@@ -24,6 +24,11 @@
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#if defined(__APPLE__)
#include <CoreFoundation/CoreFoundation.h>
#include <IOSurface/IOSurface.h>
#endif
namespace gl namespace gl
{ {
sw::Format ConvertReadFormatType(GLenum format, GLenum type) sw::Format ConvertReadFormatType(GLenum format, GLenum type)
...@@ -1205,6 +1210,195 @@ namespace egl ...@@ -1205,6 +1210,195 @@ namespace egl
return new ImageImplementation(width, height, internalformat, multiSampleDepth, lockable); return new ImageImplementation(width, height, internalformat, multiSampleDepth, lockable);
} }
int ClientBuffer::getWidth() const
{
return width;
}
int ClientBuffer::getHeight() const
{
return height;
}
sw::Format ClientBuffer::getFormat() const
{
return format;
}
int ClientBuffer::pitchP() const
{
#if defined(__APPLE__)
if(buffer)
{
IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
int pitchB = static_cast<int>(IOSurfaceGetBytesPerRowOfPlane(ioSurface, plane));
int bytesPerPixel = sw::Surface::bytes(format);
ASSERT((pitchB % bytesPerPixel) == 0);
return pitchB / bytesPerPixel;
}
return 0;
#else
return sw::Surface::pitchP(width, 0, format, false);
#endif
}
void ClientBuffer::retain()
{
#if defined(__APPLE__)
if(buffer)
{
CFRetain(reinterpret_cast<IOSurfaceRef>(buffer));
}
#endif
}
void ClientBuffer::release()
{
#if defined(__APPLE__)
if(buffer)
{
CFRelease(reinterpret_cast<IOSurfaceRef>(buffer));
buffer = nullptr;
}
#endif
}
void* ClientBuffer::lock(int x, int y, int z)
{
#if defined(__APPLE__)
if(buffer)
{
IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
IOSurfaceLock(ioSurface, 0, nullptr);
void* pixels = IOSurfaceGetBaseAddressOfPlane(ioSurface, plane);
int bytes = sw::Surface::bytes(format);
int pitchB = static_cast<int>(IOSurfaceGetBytesPerRowOfPlane(ioSurface, plane));
int sliceB = static_cast<int>(IOSurfaceGetHeightOfPlane(ioSurface, plane)) * pitchB;
return (unsigned char*)pixels + x * bytes + y * pitchB + z * sliceB;
}
return nullptr;
#else
int bytes = sw::Surface::bytes(format);
int pitchB = sw::Surface::pitchB(width, 0, format, false);
int sliceB = height * pitchB;
return (unsigned char*)buffer + x * bytes + y * pitchB + z * sliceB;
#endif
}
void ClientBuffer::unlock()
{
#if defined(__APPLE__)
if(buffer)
{
IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
IOSurfaceUnlock(ioSurface, 0, nullptr);
}
#endif
}
class ClientBufferImage : public egl::Image
{
public:
explicit ClientBufferImage(const ClientBuffer& clientBuffer) :
egl::Image(clientBuffer.getWidth(),
clientBuffer.getHeight(),
getClientBufferInternalFormat(clientBuffer.getFormat()),
clientBuffer.pitchP()),
clientBuffer(clientBuffer)
{
shared = false;
this->clientBuffer.retain();
}
private:
ClientBuffer clientBuffer;
~ClientBufferImage() override
{
sync(); // Wait for any threads that use this image to finish.
clientBuffer.release();
}
static GLint getClientBufferInternalFormat(sw::Format format)
{
switch(format)
{
case sw::FORMAT_R8: return GL_R8;
case sw::FORMAT_G8R8: return GL_RG8;
case sw::FORMAT_A8R8G8B8: return GL_BGRA8_EXT;
case sw::FORMAT_R16UI: return GL_R16UI;
case sw::FORMAT_A16B16G16R16F: return GL_RGBA16F;
default: return GL_NONE;
}
}
void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override
{
LOGLOCK("image=%p op=%s.swsurface lock=%d", this, __FUNCTION__, lock);
// Always do this for reference counting.
void *data = sw::Surface::lockInternal(x, y, z, lock, client);
if(x != 0 || y != 0 || z != 0)
{
LOGLOCK("badness: %s called with unsupported parms: image=%p x=%d y=%d z=%d", __FUNCTION__, this, x, y, z);
}
LOGLOCK("image=%p op=%s.ani lock=%d", this, __FUNCTION__, lock);
// Lock the ClientBuffer and use its address.
data = clientBuffer.lock(x, y, z);
if(lock == sw::LOCK_UNLOCKED)
{
// We're never going to get a corresponding unlock, so unlock
// immediately. This keeps the reference counts sane.
clientBuffer.unlock();
}
return data;
}
void unlockInternal() override
{
LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__);
clientBuffer.unlock();
LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__);
sw::Surface::unlockInternal();
}
void *lock(int x, int y, int z, sw::Lock lock) override
{
LOGLOCK("image=%p op=%s lock=%d", this, __FUNCTION__, lock);
(void)sw::Surface::lockExternal(x, y, z, lock, sw::PUBLIC);
return clientBuffer.lock(x, y, z);
}
void unlock() override
{
LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__);
clientBuffer.unlock();
LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__);
sw::Surface::unlockExternal();
}
void release() override
{
Image::release();
}
};
Image *Image::create(const egl::ClientBuffer& clientBuffer)
{
return new ClientBufferImage(clientBuffer);
}
Image::~Image() Image::~Image()
{ {
// sync() must be called in the destructor of the most derived class to ensure their vtable isn't destroyed // sync() must be called in the destructor of the most derived class to ensure their vtable isn't destroyed
......
...@@ -63,6 +63,30 @@ size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei h ...@@ -63,6 +63,30 @@ size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei h
namespace egl namespace egl
{ {
class ClientBuffer
{
public:
ClientBuffer(int width, int height, sw::Format format, void* buffer, size_t plane)
: width(width), height(height), format(format), buffer(buffer), plane(plane)
{}
int getWidth() const;
int getHeight() const;
sw::Format getFormat() const;
int pitchP() const;
void retain();
void release();
void* lock(int x, int y, int z);
void unlock();
private:
int width;
int height;
sw::Format format;
void* buffer;
size_t plane;
};
class [[clang::lto_visibility_public]] Image : public sw::Surface, public gl::Object class [[clang::lto_visibility_public]] Image : public sw::Surface, public gl::Object
{ {
protected: protected:
...@@ -117,6 +141,9 @@ public: ...@@ -117,6 +141,9 @@ public:
// Render target // Render target
static Image *create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable); static Image *create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable);
// Back buffer from client buffer
static Image *create(const egl::ClientBuffer& clientBuffer);
GLsizei getWidth() const GLsizei getWidth() const
{ {
return width; return width;
......
...@@ -42,6 +42,7 @@ public: ...@@ -42,6 +42,7 @@ public:
virtual EGLint getWidth() const = 0; virtual EGLint getWidth() const = 0;
virtual EGLint getHeight() const = 0; virtual EGLint getHeight() const = 0;
virtual EGLenum getTextureTarget() const = 0;
virtual void setBoundTexture(egl::Texture *texture) = 0; virtual void setBoundTexture(egl::Texture *texture) = 0;
}; };
......
...@@ -67,6 +67,8 @@ swiftshader_shared_library("swiftshader_libEGL") { ...@@ -67,6 +67,8 @@ swiftshader_shared_library("swiftshader_libEGL") {
libs = [ libs = [
"Quartz.framework", "Quartz.framework",
"Cocoa.framework", "Cocoa.framework",
"CoreFoundation.framework",
"IOSurface.framework",
] ]
ldflags = [ "-Wl,-install_name,@rpath/libswiftshader_libEGL.dylib" ] ldflags = [ "-Wl,-install_name,@rpath/libswiftshader_libEGL.dylib" ]
} else if (is_win) { } else if (is_win) {
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include "Main/libX11.hpp" #include "Main/libX11.hpp"
#elif defined(__APPLE__) #elif defined(__APPLE__)
#include "OSXUtils.hpp" #include "OSXUtils.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <IOSurface/IOSurface.h>
#endif #endif
#include <algorithm> #include <algorithm>
...@@ -338,11 +340,13 @@ EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig co ...@@ -338,11 +340,13 @@ EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig co
return success(surface); return success(surface);
} }
EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList) EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribList, EGLClientBuffer clientBuffer)
{ {
EGLint width = 0, height = 0; EGLint width = -1, height = -1, ioSurfacePlane = -1;
EGLenum textureFormat = EGL_NO_TEXTURE; EGLenum textureFormat = EGL_NO_TEXTURE;
EGLenum textureTarget = EGL_NO_TEXTURE; EGLenum textureTarget = EGL_NO_TEXTURE;
EGLenum clientBufferFormat = EGL_NO_TEXTURE;
EGLenum clientBufferType = EGL_NO_TEXTURE;
EGLBoolean largestPBuffer = EGL_FALSE; EGLBoolean largestPBuffer = EGL_FALSE;
const Config *configuration = mConfigSet.get(config); const Config *configuration = mConfigSet.get(config);
...@@ -373,11 +377,45 @@ EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribL ...@@ -373,11 +377,45 @@ EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribL
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
} }
break; break;
case EGL_TEXTURE_INTERNAL_FORMAT_ANGLE:
switch(attribList[1])
{
case GL_RED:
case GL_R16UI:
case GL_RG:
case GL_BGRA_EXT:
case GL_RGBA:
clientBufferFormat = attribList[1];
break;
default:
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
break;
case EGL_TEXTURE_TYPE_ANGLE:
switch(attribList[1])
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT:
case GL_HALF_FLOAT:
clientBufferType = attribList[1];
break;
default:
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
break;
case EGL_IOSURFACE_PLANE_ANGLE:
if(attribList[1] < 0)
{
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
ioSurfacePlane = attribList[1];
break;
case EGL_TEXTURE_TARGET: case EGL_TEXTURE_TARGET:
switch(attribList[1]) switch(attribList[1])
{ {
case EGL_NO_TEXTURE: case EGL_NO_TEXTURE:
case EGL_TEXTURE_2D: case EGL_TEXTURE_2D:
case EGL_TEXTURE_RECTANGLE_ANGLE:
textureTarget = attribList[1]; textureTarget = attribList[1];
break; break;
default: default:
...@@ -423,13 +461,92 @@ EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribL ...@@ -423,13 +461,92 @@ EGLSurface Display::createPBufferSurface(EGLConfig config, const EGLint *attribL
return error(EGL_BAD_MATCH, EGL_NO_SURFACE); return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
} }
if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || if(clientBuffer)
(textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
{ {
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); switch(clientBufferType)
{
case GL_UNSIGNED_BYTE:
switch(clientBufferFormat)
{
case GL_RED:
case GL_RG:
case GL_BGRA_EXT:
break;
case GL_R16UI:
case GL_RGBA:
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
default:
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
break;
case GL_UNSIGNED_SHORT:
switch(clientBufferFormat)
{
case GL_R16UI:
break;
case GL_RED:
case GL_RG:
case GL_BGRA_EXT:
case GL_RGBA:
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
default:
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
break;
case GL_HALF_FLOAT:
switch(clientBufferFormat)
{
case GL_RGBA:
break;
case GL_RED:
case GL_R16UI:
case GL_RG:
case GL_BGRA_EXT:
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
default:
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
break;
default:
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
if(ioSurfacePlane < 0)
{
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
}
if(textureFormat != EGL_TEXTURE_RGBA)
{
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
if(textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE)
{
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
#if defined(__APPLE__)
IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(clientBuffer);
size_t planeCount = IOSurfaceGetPlaneCount(ioSurface);
if((static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, ioSurfacePlane)) ||
(static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, ioSurfacePlane)) ||
((planeCount != 0) && static_cast<size_t>(ioSurfacePlane) >= planeCount))
{
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
#endif
}
else
{
if((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
((textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)))
{
return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
} }
Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, largestPBuffer); Surface *surface = new PBufferSurface(this, configuration, width, height, textureFormat, textureTarget, clientBufferFormat, clientBufferType, largestPBuffer, clientBuffer, ioSurfacePlane);
if(!surface->initialize()) if(!surface->initialize())
{ {
......
...@@ -26,6 +26,15 @@ ...@@ -26,6 +26,15 @@
#include <set> #include <set>
#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
namespace egl namespace egl
{ {
class Surface; class Surface;
...@@ -51,7 +60,7 @@ namespace egl ...@@ -51,7 +60,7 @@ namespace egl
bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value);
EGLSurface createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList); EGLSurface createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList);
EGLSurface createPBufferSurface(EGLConfig config, const EGLint *attribList); EGLSurface createPBufferSurface(EGLConfig config, const EGLint *attribList, EGLClientBuffer clientBuffer = nullptr);
EGLContext createContext(EGLConfig configHandle, const Context *shareContext, EGLint clientVersion); EGLContext createContext(EGLConfig configHandle, const Context *shareContext, EGLint clientVersion);
EGLSyncKHR createSync(Context *context); EGLSyncKHR createSync(Context *context);
......
...@@ -63,6 +63,10 @@ Surface::Surface(const Display *display, const Config *config) : display(display ...@@ -63,6 +63,10 @@ Surface::Surface(const Display *display, const Config *config) : display(display
swapBehavior = EGL_BUFFER_PRESERVED; swapBehavior = EGL_BUFFER_PRESERVED;
textureFormat = EGL_NO_TEXTURE; textureFormat = EGL_NO_TEXTURE;
textureTarget = EGL_NO_TEXTURE; textureTarget = EGL_NO_TEXTURE;
clientBufferFormat = EGL_NO_TEXTURE;
clientBufferType = EGL_NO_TEXTURE;
clientBuffer = nullptr;
clientBufferPlane = -1;
swapInterval = -1; swapInterval = -1;
setSwapInterval(1); setSwapInterval(1);
} }
...@@ -78,7 +82,15 @@ bool Surface::initialize() ...@@ -78,7 +82,15 @@ bool Surface::initialize()
if(libGLESv2) if(libGLESv2)
{ {
backBuffer = libGLESv2->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples); if(clientBuffer)
{
backBuffer = libGLESv2->createBackBufferFromClientBuffer(
egl::ClientBuffer(width, height, getClientBufferFormat(), clientBuffer, clientBufferPlane));
}
else
{
backBuffer = libGLESv2->createBackBuffer(width, height, config->mRenderTargetFormat, config->mSamples);
}
} }
else if(libGLES_CM) else if(libGLES_CM)
{ {
...@@ -222,6 +234,51 @@ EGLBoolean Surface::getLargestPBuffer() const ...@@ -222,6 +234,51 @@ EGLBoolean Surface::getLargestPBuffer() const
return largestPBuffer; return largestPBuffer;
} }
sw::Format Surface::getClientBufferFormat() const
{
switch(clientBufferType)
{
case GL_UNSIGNED_BYTE:
switch(clientBufferFormat)
{
case GL_RED:
return sw::FORMAT_R8;
case GL_RG:
return sw::FORMAT_G8R8;
case GL_BGRA_EXT:
return sw::FORMAT_A8R8G8B8;
default:
UNREACHABLE(clientBufferFormat);
break;
}
break;
case GL_UNSIGNED_SHORT:
switch(clientBufferFormat)
{
case GL_R16UI:
return sw::FORMAT_R16UI;
default:
UNREACHABLE(clientBufferFormat);
break;
}
break;
case GL_HALF_FLOAT:
switch(clientBufferFormat)
{
case GL_RGBA:
return sw::FORMAT_A16B16G16R16F;
default:
UNREACHABLE(clientBufferFormat);
break;
}
default:
UNREACHABLE(clientBufferType);
break;
}
return sw::FORMAT_NULL;
}
void Surface::setBoundTexture(egl::Texture *texture) void Surface::setBoundTexture(egl::Texture *texture)
{ {
this->texture = texture; this->texture = texture;
...@@ -356,12 +413,21 @@ bool WindowSurface::reset(int backBufferWidth, int backBufferHeight) ...@@ -356,12 +413,21 @@ bool WindowSurface::reset(int backBufferWidth, int backBufferHeight)
return Surface::initialize(); return Surface::initialize();
} }
PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType, EGLBoolean largestPBuffer) PBufferSurface::PBufferSurface(Display *display, const Config *config, EGLint width, EGLint height,
EGLenum textureFormat, EGLenum textureTarget, EGLenum clientBufferFormat,
EGLenum clientBufferType, EGLBoolean largestPBuffer, EGLClientBuffer clientBuffer,
EGLint clientBufferPlane)
: Surface(display, config) : Surface(display, config)
{ {
this->width = width; this->width = width;
this->height = height; this->height = height;
this->largestPBuffer = largestPBuffer; this->largestPBuffer = largestPBuffer;
this->textureFormat = textureFormat;
this->textureTarget = textureTarget;
this->clientBufferFormat = clientBufferFormat;
this->clientBufferType = clientBufferType;
this->clientBuffer = clientBuffer;
this->clientBufferPlane = clientBufferPlane;
} }
PBufferSurface::~PBufferSurface() PBufferSurface::~PBufferSurface()
......
...@@ -48,11 +48,11 @@ public: ...@@ -48,11 +48,11 @@ public:
EGLint getWidth() const override; EGLint getWidth() const override;
EGLint getHeight() const override; EGLint getHeight() const override;
EGLenum getTextureTarget() const override;
virtual EGLint getPixelAspectRatio() const; virtual EGLint getPixelAspectRatio() const;
virtual EGLenum getRenderBuffer() const; virtual EGLenum getRenderBuffer() const;
virtual EGLenum getSwapBehavior() const; virtual EGLenum getSwapBehavior() const;
virtual EGLenum getTextureFormat() const; virtual EGLenum getTextureFormat() const;
virtual EGLenum getTextureTarget() const;
virtual EGLBoolean getLargestPBuffer() const; virtual EGLBoolean getLargestPBuffer() const;
virtual EGLNativeWindowType getWindowHandle() const = 0; virtual EGLNativeWindowType getWindowHandle() const = 0;
...@@ -61,6 +61,7 @@ public: ...@@ -61,6 +61,7 @@ public:
virtual bool isWindowSurface() const { return false; } virtual bool isWindowSurface() const { return false; }
virtual bool isPBufferSurface() const { return false; } virtual bool isPBufferSurface() const { return false; }
bool hasClientBuffer() const { return clientBuffer != nullptr; }
protected: protected:
Surface(const Display *display, const Config *config); Surface(const Display *display, const Config *config);
...@@ -69,6 +70,8 @@ protected: ...@@ -69,6 +70,8 @@ protected:
virtual void deleteResources(); virtual void deleteResources();
sw::Format getClientBufferFormat() const;
const Display *const display; const Display *const display;
Image *depthStencil; Image *depthStencil;
Image *backBuffer; Image *backBuffer;
...@@ -77,8 +80,8 @@ protected: ...@@ -77,8 +80,8 @@ protected:
bool reset(int backbufferWidth, int backbufferHeight); bool reset(int backbufferWidth, int backbufferHeight);
const Config *const config; // EGL config surface was created with const Config *const config; // EGL config surface was created with
EGLint height; // Height of surface
EGLint width; // Width of surface EGLint width; // Width of surface
EGLint height; // Height of surface
// EGLint horizontalResolution; // Horizontal dot pitch // EGLint horizontalResolution; // Horizontal dot pitch
// EGLint verticalResolution; // Vertical dot pitch // EGLint verticalResolution; // Vertical dot pitch
EGLBoolean largestPBuffer; // If true, create largest pbuffer possible EGLBoolean largestPBuffer; // If true, create largest pbuffer possible
...@@ -90,9 +93,13 @@ protected: ...@@ -90,9 +93,13 @@ protected:
EGLenum swapBehavior; // Buffer swap behavior EGLenum swapBehavior; // Buffer swap behavior
EGLenum textureFormat; // Format of texture: RGB, RGBA, or no texture EGLenum textureFormat; // Format of texture: RGB, RGBA, or no texture
EGLenum textureTarget; // Type of texture: 2D or no texture EGLenum textureTarget; // Type of texture: 2D or no texture
EGLenum clientBufferFormat; // Format of the client buffer
EGLenum clientBufferType; // Type of the client buffer
// EGLenum vgAlphaFormat; // Alpha format for OpenVG // EGLenum vgAlphaFormat; // Alpha format for OpenVG
// EGLenum vgColorSpace; // Color space for OpenVG // EGLenum vgColorSpace; // Color space for OpenVG
EGLint swapInterval; EGLint swapInterval;
EGLClientBuffer clientBuffer;
EGLint clientBufferPlane;
}; };
class WindowSurface : public Surface class WindowSurface : public Surface
...@@ -120,7 +127,10 @@ private: ...@@ -120,7 +127,10 @@ private:
class PBufferSurface : public Surface class PBufferSurface : public Surface
{ {
public: public:
PBufferSurface(Display *display, const egl::Config *config, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureTarget, EGLBoolean largestPBuffer); PBufferSurface(Display *display, const egl::Config *config, EGLint width, EGLint height,
EGLenum textureFormat, EGLenum textureTarget, EGLenum internalFormat,
EGLenum textureType, EGLBoolean largestPBuffer, EGLClientBuffer clientBuffer,
EGLint clientBufferPlane);
~PBufferSurface() override; ~PBufferSurface() override;
bool isPBufferSurface() const override { return true; } bool isPBufferSurface() const override { return true; }
......
...@@ -204,6 +204,7 @@ const char *QueryString(EGLDisplay dpy, EGLint name) ...@@ -204,6 +204,7 @@ const char *QueryString(EGLDisplay dpy, EGLint name)
"EGL_KHR_fence_sync " "EGL_KHR_fence_sync "
"EGL_KHR_image_base " "EGL_KHR_image_base "
"EGL_KHR_surfaceless_context " "EGL_KHR_surfaceless_context "
"EGL_ANGLE_iosurface_client_buffer "
"EGL_ANDROID_framebuffer_target " "EGL_ANDROID_framebuffer_target "
"EGL_ANDROID_recordable"); "EGL_ANDROID_recordable");
case EGL_VENDOR: case EGL_VENDOR:
...@@ -507,9 +508,25 @@ EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLCli ...@@ -507,9 +508,25 @@ EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLCli
"EGLConfig config = %p, const EGLint *attrib_list = %p)", "EGLConfig config = %p, const EGLint *attrib_list = %p)",
dpy, buftype, buffer, config, attrib_list); dpy, buftype, buffer, config, attrib_list);
UNIMPLEMENTED(); switch(buftype)
{
case EGL_IOSURFACE_ANGLE:
{
egl::Display *display = egl::Display::get(dpy);
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); if(!validateConfig(display, config))
{
return EGL_NO_SURFACE;
}
return display->createPBufferSurface(config, attrib_list, buffer);
}
case EGL_OPENVG_IMAGE:
UNIMPLEMENTED();
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
default:
return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
};
} }
EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
...@@ -810,6 +827,13 @@ EGLBoolean MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLCont ...@@ -810,6 +827,13 @@ EGLBoolean MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLCont
return EGL_FALSE; return EGL_FALSE;
} }
if((draw != EGL_NO_SURFACE && drawSurface->hasClientBuffer()) ||
(read != EGL_NO_SURFACE && readSurface->hasClientBuffer()))
{
// Make current is not supported on IOSurface pbuffers.
return error(EGL_BAD_SURFACE, EGL_FALSE);
}
if((draw != EGL_NO_SURFACE) ^ (read != EGL_NO_SURFACE)) if((draw != EGL_NO_SURFACE) ^ (read != EGL_NO_SURFACE))
{ {
return error(EGL_BAD_MATCH, EGL_FALSE); return error(EGL_BAD_MATCH, EGL_FALSE);
......
...@@ -109,6 +109,10 @@ swiftshader_shared_library("swiftshader_libGLESv2") { ...@@ -109,6 +109,10 @@ swiftshader_shared_library("swiftshader_libGLESv2") {
if (is_win) { if (is_win) {
ldflags = [ "/DEF:" + rebase_path("libGLESv2.def", root_build_dir) ] ldflags = [ "/DEF:" + rebase_path("libGLESv2.def", root_build_dir) ]
} else if (is_mac) { } else if (is_mac) {
libs = [
"CoreFoundation.framework",
"IOSurface.framework",
]
ldflags = [ "-Wl,-install_name,@rpath/libswiftshader_libGLESv2.dylib" ] ldflags = [ "-Wl,-install_name,@rpath/libswiftshader_libGLESv2.dylib" ]
} else if (is_linux) { } else if (is_linux) {
ldflags = ldflags =
......
...@@ -4093,8 +4093,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -4093,8 +4093,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
{ {
GLenum readColorbufferType = readFramebuffer->getReadBufferType(); GLenum readColorbufferType = readFramebuffer->getReadBufferType();
GLenum drawColorbufferType = drawFramebuffer->getColorbufferType(0); GLenum drawColorbufferType = drawFramebuffer->getColorbufferType(0);
const bool validReadType = readColorbufferType == GL_TEXTURE_2D || Framebuffer::IsRenderbuffer(readColorbufferType); const bool validReadType = readColorbufferType == GL_TEXTURE_2D || readColorbufferType == GL_TEXTURE_RECTANGLE_ARB || Framebuffer::IsRenderbuffer(readColorbufferType);
const bool validDrawType = drawColorbufferType == GL_TEXTURE_2D || Framebuffer::IsRenderbuffer(drawColorbufferType); const bool validDrawType = drawColorbufferType == GL_TEXTURE_2D || drawColorbufferType == GL_TEXTURE_RECTANGLE_ARB || Framebuffer::IsRenderbuffer(drawColorbufferType);
if(!validReadType || !validDrawType) if(!validReadType || !validDrawType)
{ {
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
...@@ -4145,8 +4145,10 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -4145,8 +4145,10 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
} }
if((readRenderbuffer->getSamples() > 0) && // From the ANGLE_framebuffer_blit extension:
(readRenderbuffer->getFormat() != drawRenderbuffer->getFormat())) // "Calling BlitFramebufferANGLE will result in an INVALID_OPERATION error if <mask>
// includes COLOR_BUFFER_BIT and the source and destination color formats to not match."
if((clientVersion < 3) && (readRenderbuffer->getSamples() > 0) && (readFormat != drawFormat))
{ {
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
} }
...@@ -4291,7 +4293,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1 ...@@ -4291,7 +4293,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
void Context::bindTexImage(gl::Surface *surface) void Context::bindTexImage(gl::Surface *surface)
{ {
es2::Texture2D *textureObject = getTexture2D(); bool isRect = (surface->getTextureTarget() == EGL_TEXTURE_RECTANGLE_ANGLE);
es2::Texture2D *textureObject = isRect ? getTexture2DRect() : getTexture2D();
if(textureObject) if(textureObject)
{ {
......
...@@ -1900,6 +1900,18 @@ NO_SANITIZE_FUNCTION egl::Image *createBackBuffer(int width, int height, sw::For ...@@ -1900,6 +1900,18 @@ NO_SANITIZE_FUNCTION egl::Image *createBackBuffer(int width, int height, sw::For
return egl::Image::create(width, height, internalformat, multiSampleDepth, false); return egl::Image::create(width, height, internalformat, multiSampleDepth, false);
} }
NO_SANITIZE_FUNCTION egl::Image *createBackBufferFromClientBuffer(const egl::ClientBuffer& clientBuffer)
{
if(clientBuffer.getWidth() > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
clientBuffer.getHeight() > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
{
ERR("Invalid parameters: %dx%d", clientBuffer.getWidth(), clientBuffer.getHeight());
return nullptr;
}
return egl::Image::create(clientBuffer);
}
NO_SANITIZE_FUNCTION egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth) NO_SANITIZE_FUNCTION egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth)
{ {
if(width > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE) if(width > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE || height > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
......
...@@ -1211,6 +1211,7 @@ void GL_APIENTRY Register(const char *licenseKey) ...@@ -1211,6 +1211,7 @@ void GL_APIENTRY Register(const char *licenseKey)
egl::Context *es2CreateContext(egl::Display *display, const egl::Context *shareContext, int clientVersion, const egl::Config *config); egl::Context *es2CreateContext(egl::Display *display, const egl::Context *shareContext, int clientVersion, const egl::Config *config);
extern "C" __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname); extern "C" __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname);
egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth); egl::Image *createBackBuffer(int width, int height, sw::Format format, int multiSampleDepth);
egl::Image *createBackBufferFromClientBuffer(const egl::ClientBuffer& clientBuffer);
egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth); egl::Image *createDepthStencil(int width, int height, sw::Format format, int multiSampleDepth);
sw::FrameBuffer *createFrameBuffer(void *nativeDisplay, EGLNativeWindowType window, int width, int height); sw::FrameBuffer *createFrameBuffer(void *nativeDisplay, EGLNativeWindowType window, int width, int height);
...@@ -1414,6 +1415,7 @@ LibGLESv2exports::LibGLESv2exports() ...@@ -1414,6 +1415,7 @@ LibGLESv2exports::LibGLESv2exports()
this->es2CreateContext = ::es2CreateContext; this->es2CreateContext = ::es2CreateContext;
this->es2GetProcAddress = ::es2GetProcAddress; this->es2GetProcAddress = ::es2GetProcAddress;
this->createBackBuffer = ::createBackBuffer; this->createBackBuffer = ::createBackBuffer;
this->createBackBufferFromClientBuffer = ::createBackBufferFromClientBuffer;
this->createDepthStencil = ::createDepthStencil; this->createDepthStencil = ::createDepthStencil;
this->createFrameBuffer = ::createFrameBuffer; this->createFrameBuffer = ::createFrameBuffer;
} }
......
...@@ -33,6 +33,7 @@ class Display; ...@@ -33,6 +33,7 @@ class Display;
class Context; class Context;
class Image; class Image;
class Config; class Config;
class ClientBuffer;
} }
class LibGLESv2exports class LibGLESv2exports
...@@ -245,6 +246,7 @@ public: ...@@ -245,6 +246,7 @@ public:
egl::Context *(*es2CreateContext)(egl::Display *display, const egl::Context *shareContext, int clientVersion, const egl::Config *config); egl::Context *(*es2CreateContext)(egl::Display *display, const egl::Context *shareContext, int clientVersion, const egl::Config *config);
__eglMustCastToProperFunctionPointerType (*es2GetProcAddress)(const char *procname); __eglMustCastToProperFunctionPointerType (*es2GetProcAddress)(const char *procname);
egl::Image *(*createBackBuffer)(int width, int height, sw::Format format, int multiSampleDepth); egl::Image *(*createBackBuffer)(int width, int height, sw::Format format, int multiSampleDepth);
egl::Image *(*createBackBufferFromClientBuffer)(const egl::ClientBuffer& clientBuffer);
egl::Image *(*createDepthStencil)(int width, int height, sw::Format format, int multiSampleDepth); egl::Image *(*createDepthStencil)(int width, int height, sw::Format format, int multiSampleDepth);
sw::FrameBuffer *(*createFrameBuffer)(void *nativeDisplay, EGLNativeWindowType window, int width, int height); sw::FrameBuffer *(*createFrameBuffer)(void *nativeDisplay, EGLNativeWindowType window, int width, int height);
}; };
......
...@@ -46,6 +46,10 @@ test("swiftshader_unittests") { ...@@ -46,6 +46,10 @@ test("swiftshader_unittests") {
"-rpath", "-rpath",
"@executable_path/", "@executable_path/",
] ]
libs = [
"CoreFoundation.framework",
"IOSurface.framework",
]
} else { } else {
ldflags = [ "-Wl,-rpath=\$ORIGIN/swiftshader" ] ldflags = [ "-Wl,-rpath=\$ORIGIN/swiftshader" ]
} }
......
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