Commit 22a4f38c by Geoff Lang

Implement the egl and gl layers of EGL Image.

Add end2end tests and unittests. BUG=angleproject:970 Change-Id: I13fc501b24c3f11bfedc810c1ff80fcf1318877c Reviewed-on: https://chromium-review.googlesource.com/287343Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 6b2a0b0c
...@@ -555,6 +555,99 @@ std::string ParseUniformName(const std::string &name, size_t *outSubscript) ...@@ -555,6 +555,99 @@ std::string ParseUniformName(const std::string &name, size_t *outSubscript)
} }
namespace egl
{
static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 1,
"Unexpected EGL cube map enum value.");
static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 2,
"Unexpected EGL cube map enum value.");
static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 3,
"Unexpected EGL cube map enum value.");
static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 4,
"Unexpected EGL cube map enum value.");
static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 5,
"Unexpected EGL cube map enum value.");
bool IsCubeMapTextureTarget(EGLenum target)
{
return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget);
}
size_t CubeMapTextureTargetToLayerIndex(EGLenum target)
{
ASSERT(IsCubeMapTextureTarget(target));
return target - static_cast<size_t>(FirstCubeMapTextureTarget);
}
EGLenum LayerIndexToCubeMapTextureTarget(size_t index)
{
ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget));
return FirstCubeMapTextureTarget + static_cast<GLenum>(index);
}
bool IsTextureTarget(EGLenum target)
{
switch (target)
{
case EGL_GL_TEXTURE_2D_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
case EGL_GL_TEXTURE_3D_KHR:
return true;
default:
return false;
}
}
bool IsRenderbufferTarget(EGLenum target)
{
return target == EGL_GL_RENDERBUFFER_KHR;
}
}
namespace egl_gl
{
GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget)
{
ASSERT(egl::IsCubeMapTextureTarget(eglTarget));
return gl::LayerIndexToCubeMapTextureTarget(egl::CubeMapTextureTargetToLayerIndex(eglTarget));
}
GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget)
{
switch (eglTarget)
{
case EGL_GL_TEXTURE_2D_KHR:
return GL_TEXTURE_2D;
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
return EGLCubeMapTargetToGLCubeMapTarget(eglTarget);
case EGL_GL_TEXTURE_3D_KHR:
return GL_TEXTURE_3D;
default:
UNREACHABLE();
return GL_NONE;
}
}
GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer)
{
return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
}
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE) #if !defined(ANGLE_ENABLE_WINDOWS_STORE)
std::string getTempPath() std::string getTempPath()
{ {
......
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
#ifndef COMMON_UTILITIES_H_ #ifndef COMMON_UTILITIES_H_
#define COMMON_UTILITIES_H_ #define COMMON_UTILITIES_H_
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "angle_gl.h" #include "angle_gl.h"
#include <string> #include <string>
#include <math.h> #include <math.h>
...@@ -59,6 +62,24 @@ template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>( ...@@ -59,6 +62,24 @@ template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(
} }
namespace egl
{
static const EGLenum FirstCubeMapTextureTarget = EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR;
static const EGLenum LastCubeMapTextureTarget = EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR;
bool IsCubeMapTextureTarget(EGLenum target);
size_t CubeMapTextureTargetToLayerIndex(EGLenum target);
EGLenum LayerIndexToCubeMapTextureTarget(size_t index);
bool IsTextureTarget(EGLenum target);
bool IsRenderbufferTarget(EGLenum target);
}
namespace egl_gl
{
GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget);
GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget);
GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer);
}
#if !defined(ANGLE_ENABLE_WINDOWS_STORE) #if !defined(ANGLE_ENABLE_WINDOWS_STORE)
std::string getTempPath(); std::string getTempPath();
void writeFile(const char* path, const void* data, size_t size); void writeFile(const char* path, const void* data, size_t size);
......
...@@ -22,11 +22,14 @@ ...@@ -22,11 +22,14 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/mathutil.h" #include "common/mathutil.h"
#include "common/platform.h" #include "common/platform.h"
#include "common/utilities.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Device.h" #include "libANGLE/Device.h"
#include "libANGLE/histogram_macros.h" #include "libANGLE/histogram_macros.h"
#include "libANGLE/Image.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include "libANGLE/renderer/DisplayImpl.h" #include "libANGLE/renderer/DisplayImpl.h"
#include "libANGLE/renderer/ImageImpl.h"
#include "third_party/trace_event/trace_event.h" #include "third_party/trace_event/trace_event.h"
#if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11) #if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_D3D11)
...@@ -303,6 +306,11 @@ void Display::terminate() ...@@ -303,6 +306,11 @@ void Display::terminate()
destroyContext(*mContextSet.begin()); destroyContext(*mContextSet.begin());
} }
while (!mImageSet.empty())
{
destroyImage(*mImageSet.begin());
}
mConfigSet.clear(); mConfigSet.clear();
mImplementation->terminate(); mImplementation->terminate();
...@@ -508,7 +516,39 @@ Error Display::createImage(gl::Context *context, ...@@ -508,7 +516,39 @@ Error Display::createImage(gl::Context *context,
} }
} }
UNIMPLEMENTED(); egl::ImageSibling *sibling = nullptr;
if (IsTextureTarget(target))
{
sibling = context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
}
else if (IsRenderbufferTarget(target))
{
sibling = context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
}
else
{
UNREACHABLE();
}
ASSERT(sibling != nullptr);
rx::ImageImpl *imageImpl = mImplementation->createImage(target, sibling, attribs);
ASSERT(imageImpl != nullptr);
Error error = imageImpl->initialize();
if (error.isError())
{
return error;
}
Image *image = new Image(imageImpl, target, sibling, attribs);
ASSERT(outImage != nullptr);
*outImage = image;
// Add this image to the list of all images and hold a ref to it.
image->addRef();
mImageSet.insert(image);
return Error(EGL_SUCCESS); return Error(EGL_SUCCESS);
} }
...@@ -599,7 +639,10 @@ void Display::destroySurface(Surface *surface) ...@@ -599,7 +639,10 @@ void Display::destroySurface(Surface *surface)
void Display::destroyImage(egl::Image *image) void Display::destroyImage(egl::Image *image)
{ {
UNIMPLEMENTED(); auto iter = mImageSet.find(image);
ASSERT(iter != mImageSet.end());
(*iter)->release();
mImageSet.erase(iter);
} }
void Display::destroyContext(gl::Context *context) void Display::destroyContext(gl::Context *context)
...@@ -653,6 +696,11 @@ bool Display::isValidSurface(Surface *surface) const ...@@ -653,6 +696,11 @@ bool Display::isValidSurface(Surface *surface) const
return mImplementation->getSurfaceSet().find(surface) != mImplementation->getSurfaceSet().end(); return mImplementation->getSurfaceSet().find(surface) != mImplementation->getSurfaceSet().end();
} }
bool Display::isValidImage(const Image *image) const
{
return mImageSet.find(const_cast<Image *>(image)) != mImageSet.end();
}
bool Display::hasExistingWindowSurface(EGLNativeWindowType window) bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
{ {
WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
......
...@@ -79,6 +79,7 @@ class Display final : angle::NonCopyable ...@@ -79,6 +79,7 @@ class Display final : angle::NonCopyable
bool isValidConfig(const Config *config) const; bool isValidConfig(const Config *config) const;
bool isValidContext(gl::Context *context) const; bool isValidContext(gl::Context *context) const;
bool isValidSurface(egl::Surface *surface) const; bool isValidSurface(egl::Surface *surface) const;
bool isValidImage(const Image *image) const;
bool isValidNativeWindow(EGLNativeWindowType window) const; bool isValidNativeWindow(EGLNativeWindowType window) const;
static bool isValidDisplay(const egl::Display *display); static bool isValidDisplay(const egl::Display *display);
...@@ -121,6 +122,9 @@ class Display final : angle::NonCopyable ...@@ -121,6 +122,9 @@ class Display final : angle::NonCopyable
typedef std::set<gl::Context*> ContextSet; typedef std::set<gl::Context*> ContextSet;
ContextSet mContextSet; ContextSet mContextSet;
typedef std::set<Image *> ImageSet;
ImageSet mImageSet;
bool mInitialized; bool mInitialized;
Caps mCaps; Caps mCaps;
......
//
// 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.
//
// Image.cpp: Implements the egl::Image class representing the EGLimage object.
#include "libANGLE/Image.h"
#include "common/debug.h"
#include "common/utilities.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/Texture.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/renderer/ImageImpl.h"
namespace egl
{
ImageSibling::ImageSibling(GLuint id)
: gl::FramebufferAttachmentObject(id), mSourcesOf(), mTargetOf()
{
}
ImageSibling::~ImageSibling()
{
// EGL images should hold a ref to their targets and siblings, a Texture should not be deletable
// while it is attached to an EGL image.
ASSERT(mSourcesOf.empty());
orphanImages();
}
void ImageSibling::setTargetImage(egl::Image *imageTarget)
{
ASSERT(imageTarget != nullptr);
mTargetOf.set(imageTarget);
imageTarget->addTargetSibling(this);
}
gl::Error ImageSibling::orphanImages()
{
if (mTargetOf.get() != nullptr)
{
// Can't be a target and have sources.
ASSERT(mSourcesOf.empty());
gl::Error error = mTargetOf->orphanSibling(this);
if (error.isError())
{
return error;
}
mTargetOf.set(nullptr);
}
else
{
for (auto &sourceImage : mSourcesOf)
{
gl::Error error = sourceImage->orphanSibling(this);
if (error.isError())
{
return error;
}
}
mSourcesOf.clear();
}
return gl::Error(GL_NO_ERROR);
}
void ImageSibling::addImageSource(egl::Image *imageSource)
{
ASSERT(imageSource != nullptr);
mSourcesOf.insert(imageSource);
}
void ImageSibling::removeImageSource(egl::Image *imageSource)
{
ASSERT(mSourcesOf.find(imageSource) != mSourcesOf.end());
mSourcesOf.erase(imageSource);
}
Image::Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
: RefCountObject(0),
mImplementation(impl),
mInternalFormat(GL_NONE),
mWidth(0),
mHeight(0),
mSamples(0),
mSource(),
mTargets()
{
ASSERT(mImplementation != nullptr);
ASSERT(buffer != nullptr);
mSource.set(buffer);
mSource->addImageSource(this);
if (IsTextureTarget(target))
{
gl::Texture *texture = rx::GetAs<gl::Texture>(mSource.get());
GLenum textureTarget = egl_gl::EGLImageTargetToGLTextureTarget(target);
size_t level = attribs.get(EGL_GL_TEXTURE_LEVEL_KHR, 0);
mInternalFormat = texture->getInternalFormat(textureTarget, level);
mWidth = texture->getWidth(textureTarget, level);
mHeight = texture->getHeight(textureTarget, level);
mSamples = 0;
}
else if (IsRenderbufferTarget(target))
{
gl::Renderbuffer *renderbuffer = rx::GetAs<gl::Renderbuffer>(mSource.get());
mInternalFormat = renderbuffer->getInternalFormat();
mWidth = renderbuffer->getWidth();
mHeight = renderbuffer->getHeight();
mSamples = renderbuffer->getSamples();
}
else
{
UNREACHABLE();
}
}
Image::~Image()
{
SafeDelete(mImplementation);
// All targets should hold a ref to the egl image and it should not be deleted until there are
// no siblings left.
ASSERT(mTargets.empty());
// Tell the source that it is no longer used by this image
if (mSource.get() != nullptr)
{
mSource->removeImageSource(this);
mSource.set(nullptr);
}
}
void Image::addTargetSibling(ImageSibling *sibling)
{
mTargets.insert(sibling);
}
gl::Error Image::orphanSibling(ImageSibling *sibling)
{
// notify impl
gl::Error error = mImplementation->orphan(sibling);
if (mSource.get() == sibling)
{
// If the sibling is the source, it cannot be a target.
ASSERT(mTargets.find(sibling) == mTargets.end());
mSource.set(nullptr);
}
else
{
mTargets.erase(sibling);
}
return error;
}
GLenum Image::getInternalFormat() const
{
return mInternalFormat;
}
size_t Image::getWidth() const
{
return mWidth;
}
size_t Image::getHeight() const
{
return mHeight;
}
size_t Image::getSamples() const
{
return mSamples;
}
rx::ImageImpl *Image::getImplementation()
{
return mImplementation;
}
const rx::ImageImpl *Image::getImplementation() const
{
return mImplementation;
}
}
//
// 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.
//
// Image.h: Defines the egl::Image class representing the EGLimage object.
#ifndef LIBANGLE_IMAGE_H_
#define LIBANGLE_IMAGE_H_
#include "common/angleutils.h"
#include "libANGLE/AttributeMap.h"
#include "libANGLE/Error.h"
#include "libANGLE/RefCountObject.h"
#include "libANGLE/FramebufferAttachment.h"
#include <set>
namespace rx
{
class ImageImpl;
}
namespace egl
{
class Image;
class ImageSibling : public gl::FramebufferAttachmentObject
{
public:
ImageSibling(GLuint id);
virtual ~ImageSibling();
protected:
// Set the image target of this sibling
void setTargetImage(egl::Image *imageTarget);
// Orphan all EGL image sources and targets
gl::Error orphanImages();
private:
friend class Image;
// Called from Image only to add a new source image
void addImageSource(egl::Image *imageSource);
// Called from Image only to remove a source image when the Image is being deleted
void removeImageSource(egl::Image *imageSource);
std::set<Image *> mSourcesOf;
BindingPointer<Image> mTargetOf;
};
class Image final : public RefCountObject
{
public:
Image(rx::ImageImpl *impl, EGLenum target, ImageSibling *buffer, const AttributeMap &attribs);
~Image();
GLenum getInternalFormat() const;
size_t getWidth() const;
size_t getHeight() const;
size_t getSamples() const;
rx::ImageImpl *getImplementation();
const rx::ImageImpl *getImplementation() const;
private:
friend class ImageSibling;
// Called from ImageSibling only notify the image that a new target sibling exists for state
// tracking.
void addTargetSibling(ImageSibling *sibling);
// Called from ImageSibling only to notify the image that a sibling (source or target) has
// been respecified and state tracking should be updated.
gl::Error orphanSibling(ImageSibling *sibling);
rx::ImageImpl *mImplementation;
GLenum mInternalFormat;
size_t mWidth;
size_t mHeight;
size_t mSamples;
BindingPointer<ImageSibling> mSource;
std::set<ImageSibling *> mTargets;
};
}
#endif // LIBANGLE_IMAGE_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.
//
// Image_unittest.cpp : Unittets of the Image and ImageSibling classes.
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "libANGLE/Image.h"
#include "libANGLE/Texture.h"
#include "libANGLE/Renderbuffer.h"
#include "libANGLE/renderer/ImageImpl_mock.h"
#include "libANGLE/renderer/TextureImpl_mock.h"
#include "libANGLE/renderer/RenderbufferImpl_mock.h"
using ::testing::_;
using ::testing::Return;
namespace angle
{
// Verify ref counts are maintained between images and their siblings when objects are deleted
TEST(ImageTest, RefCounting)
{
// Create a texture and an EGL image that uses the texture as its source
rx::MockTextureImpl *textureImpl = new rx::MockTextureImpl();
gl::Texture *texture = new gl::Texture(textureImpl, 1, GL_TEXTURE_2D);
texture->addRef();
rx::MockImageImpl *imageImpl = new rx::MockImageImpl();
egl::Image *image = new egl::Image(imageImpl, EGL_GL_TEXTURE_2D, texture, egl::AttributeMap());
image->addRef();
// Verify that the image added a ref to the texture and the texture has not added a ref to the
// image
EXPECT_EQ(texture->getRefCount(), 2u);
EXPECT_EQ(image->getRefCount(), 1u);
// Create a renderbuffer and set it as a target of the EGL image
rx::MockRenderbufferImpl *renderbufferImpl = new rx::MockRenderbufferImpl();
gl::Renderbuffer *renderbuffer = new gl::Renderbuffer(renderbufferImpl, 1);
renderbuffer->addRef();
EXPECT_CALL(*renderbufferImpl, setStorageEGLImageTarget(_))
.WillOnce(Return(gl::Error(GL_NO_ERROR)))
.RetiresOnSaturation();
renderbuffer->setStorageEGLImageTarget(image);
// Verify that the renderbuffer added a ref to the image and the image did not add a ref to
// the renderbuffer
EXPECT_EQ(texture->getRefCount(), 2u);
EXPECT_EQ(image->getRefCount(), 2u);
EXPECT_EQ(renderbuffer->getRefCount(), 1u);
// Simulate deletion of the texture and verify that it still exists because the image holds a
// ref
texture->release();
EXPECT_EQ(texture->getRefCount(), 1u);
EXPECT_EQ(image->getRefCount(), 2u);
EXPECT_EQ(renderbuffer->getRefCount(), 1u);
// Simulate deletion of the image and verify that it still exists because the renderbuffer holds
// a ref
image->release();
EXPECT_EQ(texture->getRefCount(), 1u);
EXPECT_EQ(image->getRefCount(), 1u);
EXPECT_EQ(renderbuffer->getRefCount(), 1u);
// Simulate deletion of the renderbuffer and verify that the deletion cascades to all objects
EXPECT_CALL(*imageImpl, destructor()).Times(1).RetiresOnSaturation();
EXPECT_CALL(*imageImpl, orphan(_))
.WillOnce(Return(gl::Error(GL_NO_ERROR)))
.RetiresOnSaturation();
EXPECT_CALL(*textureImpl, destructor()).Times(1).RetiresOnSaturation();
EXPECT_CALL(*renderbufferImpl, destructor()).Times(1).RetiresOnSaturation();
renderbuffer->release();
}
// Verify that respecifiying textures releases references to the Image.
TEST(ImageTest, RespecificationReleasesReferences)
{
// Create a texture and an EGL image that uses the texture as its source
rx::MockTextureImpl *textureImpl = new rx::MockTextureImpl();
gl::Texture *texture = new gl::Texture(textureImpl, 1, GL_TEXTURE_2D);
texture->addRef();
EXPECT_CALL(*textureImpl, setImage(_, _, _, _, _, _, _, _))
.WillOnce(Return(gl::Error(GL_NO_ERROR)))
.RetiresOnSaturation();
texture->setImage(GL_TEXTURE_2D, 0, GL_RGBA8, gl::Extents(1, 1, 1), GL_RGBA, GL_UNSIGNED_BYTE,
gl::PixelUnpackState(), nullptr);
rx::MockImageImpl *imageImpl = new rx::MockImageImpl();
egl::Image *image = new egl::Image(imageImpl, EGL_GL_TEXTURE_2D, texture, egl::AttributeMap());
image->addRef();
// Verify that the image added a ref to the texture and the texture has not added a ref to the
// image
EXPECT_EQ(texture->getRefCount(), 2u);
EXPECT_EQ(image->getRefCount(), 1u);
// Respecify the texture and verify that the image releases its reference
EXPECT_CALL(*imageImpl, orphan(_))
.WillOnce(Return(gl::Error(GL_NO_ERROR)))
.RetiresOnSaturation();
EXPECT_CALL(*textureImpl, setImage(_, _, _, _, _, _, _, _))
.WillOnce(Return(gl::Error(GL_NO_ERROR)))
.RetiresOnSaturation();
texture->setImage(GL_TEXTURE_2D, 0, GL_RGBA8, gl::Extents(1, 1, 1), GL_RGBA, GL_UNSIGNED_BYTE,
gl::PixelUnpackState(), nullptr);
EXPECT_EQ(texture->getRefCount(), 1u);
EXPECT_EQ(image->getRefCount(), 1u);
// Delete the texture and verify that the image still exists
EXPECT_CALL(*textureImpl, destructor()).Times(1).RetiresOnSaturation();
texture->release();
EXPECT_EQ(image->getRefCount(), 1u);
// Delete the image
EXPECT_CALL(*imageImpl, destructor()).Times(1).RetiresOnSaturation();
image->release();
}
}
...@@ -12,20 +12,20 @@ ...@@ -12,20 +12,20 @@
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Image.h"
#include "libANGLE/Texture.h" #include "libANGLE/Texture.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/RenderTargetD3D.h" #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
namespace gl namespace gl
{ {
Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id)
: FramebufferAttachmentObject(id), : egl::ImageSibling(id),
mRenderbuffer(impl), mRenderbuffer(impl),
mWidth(0), mWidth(0),
mHeight(0), mHeight(0),
mInternalFormat(GL_RGBA4), mInternalFormat(GL_RGBA4),
mSamples(0) mSamples(0)
{ {
} }
...@@ -36,6 +36,8 @@ Renderbuffer::~Renderbuffer() ...@@ -36,6 +36,8 @@ Renderbuffer::~Renderbuffer()
Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t height) Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t height)
{ {
orphanImages();
Error error = mRenderbuffer->setStorage(internalformat, width, height); Error error = mRenderbuffer->setStorage(internalformat, width, height);
if (error.isError()) if (error.isError())
{ {
...@@ -52,6 +54,8 @@ Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t heigh ...@@ -52,6 +54,8 @@ Error Renderbuffer::setStorage(GLenum internalformat, size_t width, size_t heigh
Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height)
{ {
orphanImages();
Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height); Error error = mRenderbuffer->setStorageMultisample(samples, internalformat, width, height);
if (error.isError()) if (error.isError())
{ {
...@@ -66,6 +70,26 @@ Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat, ...@@ -66,6 +70,26 @@ Error Renderbuffer::setStorageMultisample(size_t samples, GLenum internalformat,
return Error(GL_NO_ERROR); return Error(GL_NO_ERROR);
} }
Error Renderbuffer::setStorageEGLImageTarget(egl::Image *image)
{
orphanImages();
Error error = mRenderbuffer->setStorageEGLImageTarget(image);
if (error.isError())
{
return error;
}
setTargetImage(image);
mWidth = image->getWidth();
mHeight = image->getHeight();
mInternalFormat = image->getInternalFormat();
mSamples = 0;
return Error(GL_NO_ERROR);
}
rx::RenderbufferImpl *Renderbuffer::getImplementation() rx::RenderbufferImpl *Renderbuffer::getImplementation()
{ {
ASSERT(mRenderbuffer); ASSERT(mRenderbuffer);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Image.h"
#include "libANGLE/renderer/RenderbufferImpl.h" #include "libANGLE/renderer/RenderbufferImpl.h"
namespace gl namespace gl
...@@ -24,7 +25,7 @@ namespace gl ...@@ -24,7 +25,7 @@ namespace gl
// FramebufferAttachment and Framebuffer for how they are applied to an FBO via an // FramebufferAttachment and Framebuffer for how they are applied to an FBO via an
// attachment point. // attachment point.
class Renderbuffer : public FramebufferAttachmentObject class Renderbuffer : public egl::ImageSibling
{ {
public: public:
Renderbuffer(rx::RenderbufferImpl *impl, GLuint id); Renderbuffer(rx::RenderbufferImpl *impl, GLuint id);
...@@ -32,6 +33,7 @@ class Renderbuffer : public FramebufferAttachmentObject ...@@ -32,6 +33,7 @@ class Renderbuffer : public FramebufferAttachmentObject
Error setStorage(GLenum internalformat, size_t width, size_t height); Error setStorage(GLenum internalformat, size_t width, size_t height);
Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height); Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height);
Error setStorageEGLImageTarget(egl::Image *imageTarget);
rx::RenderbufferImpl *getImplementation(); rx::RenderbufferImpl *getImplementation();
const rx::RenderbufferImpl *getImplementation() const; const rx::RenderbufferImpl *getImplementation() const;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "common/utilities.h" #include "common/utilities.h"
#include "libANGLE/Config.h" #include "libANGLE/Config.h"
#include "libANGLE/Data.h" #include "libANGLE/Data.h"
#include "libANGLE/Image.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
...@@ -46,7 +47,7 @@ static size_t GetImageDescIndex(GLenum target, size_t level) ...@@ -46,7 +47,7 @@ static size_t GetImageDescIndex(GLenum target, size_t level)
} }
Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target)
: FramebufferAttachmentObject(id), : egl::ImageSibling(id),
mTexture(impl), mTexture(impl),
mUsage(GL_NONE), mUsage(GL_NONE),
mImmutableLevelCount(0), mImmutableLevelCount(0),
...@@ -127,6 +128,11 @@ bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &da ...@@ -127,6 +128,11 @@ bool Texture::isSamplerComplete(const SamplerState &samplerState, const Data &da
return mCompletenessCache.samplerComplete; return mCompletenessCache.samplerComplete;
} }
bool Texture::isMipmapComplete() const
{
return computeMipmapCompleteness(mSamplerState);
}
// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
bool Texture::isCubeComplete() const bool Texture::isCubeComplete() const
{ {
...@@ -152,6 +158,22 @@ bool Texture::isCubeComplete() const ...@@ -152,6 +158,22 @@ bool Texture::isCubeComplete() const
return true; return true;
} }
size_t Texture::getMipCompleteLevels() const
{
const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0);
if (mTarget == GL_TEXTURE_3D)
{
const size_t maxDim =
std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
baseImageDesc.size.depth);
return log2(maxDim) + 1;
}
else
{
return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1;
}
}
bool Texture::isImmutable() const bool Texture::isImmutable() const
{ {
return (mImmutableLevelCount > 0); return (mImmutableLevelCount > 0);
...@@ -162,6 +184,11 @@ int Texture::immutableLevelCount() ...@@ -162,6 +184,11 @@ int Texture::immutableLevelCount()
return mImmutableLevelCount; return mImmutableLevelCount;
} }
egl::Surface *Texture::getBoundSurface() const
{
return mBoundSurface;
}
Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type, Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
const PixelUnpackState &unpack, const uint8_t *pixels) const PixelUnpackState &unpack, const uint8_t *pixels)
{ {
...@@ -169,6 +196,7 @@ Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, cons ...@@ -169,6 +196,7 @@ Error Texture::setImage(GLenum target, size_t level, GLenum internalFormat, cons
// Release from previous calls to eglBindTexImage, to avoid calling the Impl after // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages();
Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels); Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
if (error.isError()) if (error.isError())
...@@ -196,6 +224,7 @@ Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFo ...@@ -196,6 +224,7 @@ Error Texture::setCompressedImage(GLenum target, size_t level, GLenum internalFo
// Release from previous calls to eglBindTexImage, to avoid calling the Impl after // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages();
Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels); Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, imageSize, pixels);
if (error.isError()) if (error.isError())
...@@ -223,6 +252,7 @@ Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceAre ...@@ -223,6 +252,7 @@ Error Texture::copyImage(GLenum target, size_t level, const Rectangle &sourceAre
// Release from previous calls to eglBindTexImage, to avoid calling the Impl after // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages();
Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source); Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
if (error.isError()) if (error.isError())
...@@ -250,6 +280,7 @@ Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, c ...@@ -250,6 +280,7 @@ Error Texture::setStorage(GLenum target, size_t levels, GLenum internalFormat, c
// Release from previous calls to eglBindTexImage, to avoid calling the Impl after // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
releaseTexImageInternal(); releaseTexImageInternal();
orphanImages();
Error error = mTexture->setStorage(target, levels, internalFormat, size); Error error = mTexture->setStorage(target, levels, internalFormat, size);
if (error.isError()) if (error.isError())
...@@ -270,6 +301,13 @@ Error Texture::generateMipmaps() ...@@ -270,6 +301,13 @@ Error Texture::generateMipmaps()
// Release from previous calls to eglBindTexImage, to avoid calling the Impl after // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
releaseTexImageInternal(); releaseTexImageInternal();
// EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
// is not mip complete.
if (!isMipmapComplete())
{
orphanImages();
}
Error error = mTexture->generateMipmaps(getSamplerState()); Error error = mTexture->generateMipmaps(getSamplerState());
if (error.isError()) if (error.isError())
{ {
...@@ -388,22 +426,36 @@ void Texture::releaseTexImageInternal() ...@@ -388,22 +426,36 @@ void Texture::releaseTexImageInternal()
} }
} }
GLenum Texture::getBaseImageTarget() const Error Texture::setEGLImageTarget(GLenum target, egl::Image *imageTarget)
{ {
return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget; ASSERT(target == mTarget);
} ASSERT(target == GL_TEXTURE_2D);
size_t Texture::getExpectedMipLevels() const // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
{ releaseTexImageInternal();
const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), 0); orphanImages();
if (mTarget == GL_TEXTURE_3D)
{ Error error = mTexture->setEGLImageTarget(target, imageTarget);
return log2(std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height), baseImageDesc.size.depth)) + 1; if (error.isError())
}
else
{ {
return log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)) + 1; return error;
} }
setTargetImage(imageTarget);
Extents size(imageTarget->getWidth(), imageTarget->getHeight(), 1);
GLenum internalFormat = imageTarget->getInternalFormat();
GLenum type = GetInternalFormatInfo(internalFormat).type;
clearImageDescs();
setImageDesc(target, 0, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
return Error(GL_NO_ERROR);
}
GLenum Texture::getBaseImageTarget() const
{
return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
} }
bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const
...@@ -481,7 +533,7 @@ bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const ...@@ -481,7 +533,7 @@ bool Texture::computeSamplerCompleteness(const SamplerState &samplerState, const
bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const bool Texture::computeMipmapCompleteness(const gl::SamplerState &samplerState) const
{ {
size_t expectedMipLevels = getExpectedMipLevels(); size_t expectedMipLevels = getMipCompleteLevels();
size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1); size_t maxLevel = std::min<size_t>(expectedMipLevels, samplerState.maxLevel + 1);
...@@ -525,13 +577,13 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::Sa ...@@ -525,13 +577,13 @@ bool Texture::computeLevelCompleteness(GLenum target, size_t level, const gl::Sa
return false; return false;
} }
// The base image level is complete if the width and height are positive const ImageDesc &levelImageDesc = getImageDesc(target, level);
if (level == 0) if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
levelImageDesc.size.depth == 0)
{ {
return true; return false;
} }
const ImageDesc &levelImageDesc = getImageDesc(target, level);
if (levelImageDesc.internalFormat != baseImageDesc.internalFormat) if (levelImageDesc.internalFormat != baseImageDesc.internalFormat)
{ {
return false; return false;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "libANGLE/Constants.h" #include "libANGLE/Constants.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Image.h"
#include "libANGLE/angletypes.h" #include "libANGLE/angletypes.h"
#include "libANGLE/renderer/TextureImpl.h" #include "libANGLE/renderer/TextureImpl.h"
...@@ -33,7 +34,7 @@ struct Data; ...@@ -33,7 +34,7 @@ struct Data;
bool IsMipmapFiltered(const gl::SamplerState &samplerState); bool IsMipmapFiltered(const gl::SamplerState &samplerState);
class Texture final : public FramebufferAttachmentObject class Texture final : public egl::ImageSibling
{ {
public: public:
Texture(rx::TextureImpl *impl, GLuint id, GLenum target); Texture(rx::TextureImpl *impl, GLuint id, GLenum target);
...@@ -54,7 +55,9 @@ class Texture final : public FramebufferAttachmentObject ...@@ -54,7 +55,9 @@ class Texture final : public FramebufferAttachmentObject
GLenum getInternalFormat(GLenum target, size_t level) const; GLenum getInternalFormat(GLenum target, size_t level) const;
bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const; bool isSamplerComplete(const SamplerState &samplerState, const Data &data) const;
bool isMipmapComplete() const;
bool isCubeComplete() const; bool isCubeComplete() const;
size_t getMipCompleteLevels() const;
virtual Error setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type, virtual Error setImage(GLenum target, size_t level, GLenum internalFormat, const Extents &size, GLenum format, GLenum type,
const PixelUnpackState &unpack, const uint8_t *pixels); const PixelUnpackState &unpack, const uint8_t *pixels);
...@@ -73,11 +76,15 @@ class Texture final : public FramebufferAttachmentObject ...@@ -73,11 +76,15 @@ class Texture final : public FramebufferAttachmentObject
virtual Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size); virtual Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const Extents &size);
Error setEGLImageTarget(GLenum target, egl::Image *imageTarget);
virtual Error generateMipmaps(); virtual Error generateMipmaps();
bool isImmutable() const; bool isImmutable() const;
GLsizei immutableLevelCount(); GLsizei immutableLevelCount();
egl::Surface *getBoundSurface() const;
rx::TextureImpl *getImplementation() { return mTexture; } rx::TextureImpl *getImplementation() { return mTexture; }
const rx::TextureImpl *getImplementation() const { return mTexture; } const rx::TextureImpl *getImplementation() const { return mTexture; }
...@@ -114,7 +121,6 @@ class Texture final : public FramebufferAttachmentObject ...@@ -114,7 +121,6 @@ class Texture final : public FramebufferAttachmentObject
}; };
GLenum getBaseImageTarget() const; GLenum getBaseImageTarget() const;
size_t getExpectedMipLevels() const;
bool computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const; bool computeSamplerCompleteness(const SamplerState &samplerState, const Data &data) const;
bool computeMipmapCompleteness(const gl::SamplerState &samplerState) const; bool computeMipmapCompleteness(const gl::SamplerState &samplerState) const;
......
//
// 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.
//
// ImageImpl.h: Defines the rx::ImageImpl class representing the EGLimage object.
#ifndef LIBANGLE_RENDERER_IMAGEIMPL_H_
#define LIBANGLE_RENDERER_IMAGEIMPL_H_
#include "common/angleutils.h"
#include "libANGLE/Error.h"
namespace egl
{
class ImageSibling;
}
namespace rx
{
class ImageImpl : angle::NonCopyable
{
public:
virtual ~ImageImpl() {}
virtual egl::Error initialize() = 0;
virtual gl::Error orphan(egl::ImageSibling *sibling) = 0;
};
}
#endif // LIBANGLE_RENDERER_IMAGEIMPL_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.
//
// ImageImpl_mock.h: Defines a mock of the ImageImpl class.
#ifndef LIBANGLE_RENDERER_IMAGEIMPLMOCK_H_
#define LIBANGLE_RENDERER_IMAGEIMPLMOCK_H_
#include "gmock/gmock.h"
#include "libANGLE/renderer/ImageImpl.h"
namespace rx
{
class MockImageImpl : public ImageImpl
{
public:
~MockImageImpl() override { destructor(); }
MOCK_METHOD0(initialize, egl::Error(void));
MOCK_METHOD1(orphan, gl::Error(egl::ImageSibling *));
MOCK_METHOD0(destructor, void());
};
}
#endif // LIBANGLE_RENDERER_IMAGEIMPLMOCK_H_
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
namespace egl
{
class Image;
}
namespace rx namespace rx
{ {
...@@ -25,6 +30,7 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl ...@@ -25,6 +30,7 @@ class RenderbufferImpl : public FramebufferAttachmentObjectImpl
virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) = 0; virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) = 0;
virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) = 0; virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) = 0;
virtual gl::Error setStorageEGLImageTarget(egl::Image *image) = 0;
}; };
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "libANGLE/Image.h"
#include "libANGLE/renderer/RenderbufferImpl.h" #include "libANGLE/renderer/RenderbufferImpl.h"
namespace rx namespace rx
...@@ -22,6 +23,7 @@ class MockRenderbufferImpl : public RenderbufferImpl ...@@ -22,6 +23,7 @@ class MockRenderbufferImpl : public RenderbufferImpl
~MockRenderbufferImpl() override { destructor(); } ~MockRenderbufferImpl() override { destructor(); }
MOCK_METHOD3(setStorage, gl::Error(GLenum, size_t, size_t)); MOCK_METHOD3(setStorage, gl::Error(GLenum, size_t, size_t));
MOCK_METHOD4(setStorageMultisample, gl::Error(size_t, GLenum, size_t, size_t)); MOCK_METHOD4(setStorageMultisample, gl::Error(size_t, GLenum, size_t, size_t));
MOCK_METHOD1(setStorageEGLImageTarget, gl::Error(egl::Image *));
MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **)); MOCK_METHOD2(getAttachmentRenderTarget, gl::Error(const gl::FramebufferAttachment::Target &, FramebufferAttachmentRenderTarget **));
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
namespace egl namespace egl
{ {
class Surface; class Surface;
class Image;
} }
namespace gl namespace gl
...@@ -61,6 +62,8 @@ class TextureImpl : public FramebufferAttachmentObjectImpl ...@@ -61,6 +62,8 @@ class TextureImpl : public FramebufferAttachmentObjectImpl
virtual gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) = 0; virtual gl::Error setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) = 0;
virtual gl::Error setEGLImageTarget(GLenum target, egl::Image *image) = 0;
virtual gl::Error generateMipmaps(const gl::SamplerState &samplerState) = 0; virtual gl::Error generateMipmaps(const gl::SamplerState &samplerState) = 0;
virtual void bindTexImage(egl::Surface *surface) = 0; virtual void bindTexImage(egl::Surface *surface) = 0;
......
...@@ -28,6 +28,7 @@ class MockTextureImpl : public TextureImpl ...@@ -28,6 +28,7 @@ class MockTextureImpl : public TextureImpl
MOCK_METHOD5(copyImage, gl::Error(GLenum, size_t, const gl::Rectangle &, GLenum, const gl::Framebuffer *)); MOCK_METHOD5(copyImage, gl::Error(GLenum, size_t, const gl::Rectangle &, GLenum, const gl::Framebuffer *));
MOCK_METHOD5(copySubImage, gl::Error(GLenum, size_t, const gl::Offset &, const gl::Rectangle &, const gl::Framebuffer *)); MOCK_METHOD5(copySubImage, gl::Error(GLenum, size_t, const gl::Offset &, const gl::Rectangle &, const gl::Framebuffer *));
MOCK_METHOD4(setStorage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &)); MOCK_METHOD4(setStorage, gl::Error(GLenum, size_t, GLenum, const gl::Extents &));
MOCK_METHOD2(setEGLImageTarget, gl::Error(GLenum, egl::Image *));
MOCK_METHOD1(generateMipmaps, gl::Error(const gl::SamplerState &)); MOCK_METHOD1(generateMipmaps, gl::Error(const gl::SamplerState &));
MOCK_METHOD1(bindTexImage, void(egl::Surface *)); MOCK_METHOD1(bindTexImage, void(egl::Surface *));
MOCK_METHOD0(releaseTexImage, void(void)); MOCK_METHOD0(releaseTexImage, void(void));
......
...@@ -65,6 +65,12 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal ...@@ -65,6 +65,12 @@ gl::Error RenderbufferD3D::setStorageMultisample(size_t samples, GLenum internal
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error RenderbufferD3D::setStorageEGLImageTarget(egl::Image *image)
{
UNIMPLEMENTED();
return gl::Error(GL_NO_ERROR);
}
RenderTargetD3D *RenderbufferD3D::getRenderTarget() RenderTargetD3D *RenderbufferD3D::getRenderTarget()
{ {
return mRenderTarget; return mRenderTarget;
......
...@@ -26,11 +26,14 @@ class RenderbufferD3D : public RenderbufferImpl ...@@ -26,11 +26,14 @@ class RenderbufferD3D : public RenderbufferImpl
RenderbufferD3D(RendererD3D *renderer); RenderbufferD3D(RendererD3D *renderer);
virtual ~RenderbufferD3D(); virtual ~RenderbufferD3D();
virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override; gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override;
virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) override; gl::Error setStorageMultisample(size_t samples,
GLenum internalformat,
size_t width,
size_t height) override;
gl::Error setStorageEGLImageTarget(egl::Image *image) override;
RenderTargetD3D *getRenderTarget(); RenderTargetD3D *getRenderTarget();
gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target, gl::Error getAttachmentRenderTarget(const gl::FramebufferAttachment::Target &target,
FramebufferAttachmentRenderTarget **rtOut) override; FramebufferAttachmentRenderTarget **rtOut) override;
......
...@@ -969,6 +969,12 @@ void TextureD3D_2D::releaseTexImage() ...@@ -969,6 +969,12 @@ void TextureD3D_2D::releaseTexImage()
} }
} }
gl::Error TextureD3D_2D::setEGLImageTarget(GLenum target, egl::Image *image)
{
UNIMPLEMENTED();
return gl::Error(GL_NO_ERROR);
}
void TextureD3D_2D::initMipmapsImages() void TextureD3D_2D::initMipmapsImages()
{ {
// Purge array levels 1 through q and reset them to represent the generated mipmap levels. // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
...@@ -1298,6 +1304,12 @@ bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const ...@@ -1298,6 +1304,12 @@ bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
} }
gl::Error TextureD3D_Cube::setEGLImageTarget(GLenum target, egl::Image *image)
{
UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels) const gl::PixelUnpackState &unpack, const uint8_t *pixels)
{ {
...@@ -1883,6 +1895,12 @@ bool TextureD3D_3D::isDepth(GLint level) const ...@@ -1883,6 +1895,12 @@ bool TextureD3D_3D::isDepth(GLint level) const
return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
} }
gl::Error TextureD3D_3D::setEGLImageTarget(GLenum target, egl::Image *image)
{
UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels) const gl::PixelUnpackState &unpack, const uint8_t *pixels)
{ {
...@@ -2411,6 +2429,12 @@ bool TextureD3D_2DArray::isDepth(GLint level) const ...@@ -2411,6 +2429,12 @@ bool TextureD3D_2DArray::isDepth(GLint level) const
return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
} }
gl::Error TextureD3D_2DArray::setEGLImageTarget(GLenum target, egl::Image *image)
{
UNREACHABLE();
return gl::Error(GL_INVALID_OPERATION);
}
gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type, gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
const gl::PixelUnpackState &unpack, const uint8_t *pixels) const gl::PixelUnpackState &unpack, const uint8_t *pixels)
{ {
......
...@@ -147,6 +147,8 @@ class TextureD3D_2D : public TextureD3D ...@@ -147,6 +147,8 @@ class TextureD3D_2D : public TextureD3D
virtual void bindTexImage(egl::Surface *surface); virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage(); virtual void releaseTexImage();
gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
virtual gl::ImageIndexIterator imageIterator() const; virtual gl::ImageIndexIterator imageIterator() const;
...@@ -209,6 +211,8 @@ class TextureD3D_Cube : public TextureD3D ...@@ -209,6 +211,8 @@ class TextureD3D_Cube : public TextureD3D
virtual void bindTexImage(egl::Surface *surface); virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage(); virtual void releaseTexImage();
gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
virtual gl::ImageIndexIterator imageIterator() const; virtual gl::ImageIndexIterator imageIterator() const;
...@@ -270,6 +274,8 @@ class TextureD3D_3D : public TextureD3D ...@@ -270,6 +274,8 @@ class TextureD3D_3D : public TextureD3D
virtual void bindTexImage(egl::Surface *surface); virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage(); virtual void releaseTexImage();
gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
virtual gl::ImageIndexIterator imageIterator() const; virtual gl::ImageIndexIterator imageIterator() const;
...@@ -329,6 +335,8 @@ class TextureD3D_2DArray : public TextureD3D ...@@ -329,6 +335,8 @@ class TextureD3D_2DArray : public TextureD3D
virtual void bindTexImage(egl::Surface *surface); virtual void bindTexImage(egl::Surface *surface);
virtual void releaseTexImage(); virtual void releaseTexImage();
gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT); virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT);
virtual gl::ImageIndexIterator imageIterator() const; virtual gl::ImageIndexIterator imageIterator() const;
......
...@@ -81,6 +81,12 @@ gl::Error RenderbufferGL::setStorageMultisample(size_t samples, GLenum internalf ...@@ -81,6 +81,12 @@ gl::Error RenderbufferGL::setStorageMultisample(size_t samples, GLenum internalf
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error RenderbufferGL::setStorageEGLImageTarget(egl::Image *image)
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
GLuint RenderbufferGL::getRenderbufferID() const GLuint RenderbufferGL::getRenderbufferID() const
{ {
return mRenderbufferID; return mRenderbufferID;
......
...@@ -34,6 +34,7 @@ class RenderbufferGL : public RenderbufferImpl ...@@ -34,6 +34,7 @@ class RenderbufferGL : public RenderbufferImpl
virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override; virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override;
virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) override; virtual gl::Error setStorageMultisample(size_t samples, GLenum internalformat, size_t width, size_t height) override;
virtual gl::Error setStorageEGLImageTarget(egl::Image *image) override;
GLuint getRenderbufferID() const; GLuint getRenderbufferID() const;
......
...@@ -418,6 +418,12 @@ void TextureGL::releaseTexImage() ...@@ -418,6 +418,12 @@ void TextureGL::releaseTexImage()
} }
} }
gl::Error TextureGL::setEGLImageTarget(GLenum target, egl::Image *image)
{
UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION);
}
template <typename T> template <typename T>
static inline void SyncSamplerStateMember(const FunctionsGL *functions, const gl::SamplerState &newState, static inline void SyncSamplerStateMember(const FunctionsGL *functions, const gl::SamplerState &newState,
gl::SamplerState &curState, GLenum textureType, GLenum name, gl::SamplerState &curState, GLenum textureType, GLenum name,
......
...@@ -52,6 +52,8 @@ class TextureGL : public TextureImpl ...@@ -52,6 +52,8 @@ class TextureGL : public TextureImpl
void bindTexImage(egl::Surface *surface) override; void bindTexImage(egl::Surface *surface) override;
void releaseTexImage() override; void releaseTexImage() override;
gl::Error setEGLImageTarget(GLenum target, egl::Image *image) override;
void syncSamplerState(const gl::SamplerState &samplerState) const; void syncSamplerState(const gl::SamplerState &samplerState) const;
GLuint getTextureID() const; GLuint getTextureID() const;
......
...@@ -32,6 +32,7 @@ Error ValidateDisplay(const Display *display); ...@@ -32,6 +32,7 @@ Error ValidateDisplay(const Display *display);
Error ValidateSurface(const Display *display, Surface *surface); Error ValidateSurface(const Display *display, Surface *surface);
Error ValidateConfig(const Display *display, const Config *config); Error ValidateConfig(const Display *display, const Config *config);
Error ValidateContext(const Display *display, gl::Context *context); Error ValidateContext(const Display *display, gl::Context *context);
Error ValidateImage(const Display *display, const Image *image);
// Entry point validation // Entry point validation
Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext,
......
...@@ -10,10 +10,12 @@ ...@@ -10,10 +10,12 @@
#include "libANGLE/validationES2.h" #include "libANGLE/validationES2.h"
#include "libANGLE/validationES3.h" #include "libANGLE/validationES3.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/Texture.h" #include "libANGLE/Texture.h"
#include "libANGLE/Framebuffer.h" #include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/Image.h"
#include "libANGLE/Query.h" #include "libANGLE/Query.h"
#include "libANGLE/Program.h" #include "libANGLE/Program.h"
#include "libANGLE/Uniform.h" #include "libANGLE/Uniform.h"
...@@ -2006,7 +2008,43 @@ bool ValidateEGLImageTargetTexture2DOES(Context *context, ...@@ -2006,7 +2008,43 @@ bool ValidateEGLImageTargetTexture2DOES(Context *context,
GLenum target, GLenum target,
egl::Image *image) egl::Image *image)
{ {
UNIMPLEMENTED(); if (!context->getExtensions().eglImage && !context->getExtensions().eglImageExternal)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
switch (target)
{
case GL_TEXTURE_2D:
break;
default:
context->recordError(Error(GL_INVALID_ENUM, "invalid texture target."));
return false;
}
if (!display->isValidImage(image))
{
context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
return false;
}
if (image->getSamples() > 0)
{
context->recordError(Error(GL_INVALID_OPERATION,
"cannot create a 2D texture from a multisampled EGL image."));
return false;
}
const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
if (!textureCaps.texturable)
{
context->recordError(Error(GL_INVALID_OPERATION,
"EGL image internal format is not supported as a texture."));
return false;
}
return true; return true;
} }
...@@ -2015,7 +2053,36 @@ bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context, ...@@ -2015,7 +2053,36 @@ bool ValidateEGLImageTargetRenderbufferStorageOES(Context *context,
GLenum target, GLenum target,
egl::Image *image) egl::Image *image)
{ {
UNIMPLEMENTED(); if (!context->getExtensions().eglImage)
{
context->recordError(Error(GL_INVALID_OPERATION));
return false;
}
switch (target)
{
case GL_RENDERBUFFER:
break;
default:
context->recordError(Error(GL_INVALID_ENUM, "invalid renderbuffer target."));
return false;
}
if (!display->isValidImage(image))
{
context->recordError(Error(GL_INVALID_VALUE, "EGL image is not valid."));
return false;
}
const TextureCaps &textureCaps = context->getTextureCaps().get(image->getInternalFormat());
if (!textureCaps.renderable)
{
context->recordError(Error(
GL_INVALID_OPERATION, "EGL image internal format is not supported as a renderbuffer."));
return false;
}
return true; return true;
} }
} }
...@@ -82,6 +82,8 @@ ...@@ -82,6 +82,8 @@
'libANGLE/FramebufferAttachment.h', 'libANGLE/FramebufferAttachment.h',
'libANGLE/HandleAllocator.cpp', 'libANGLE/HandleAllocator.cpp',
'libANGLE/HandleAllocator.h', 'libANGLE/HandleAllocator.h',
'libANGLE/Image.h',
'libANGLE/Image.cpp',
'libANGLE/ImageIndex.h', 'libANGLE/ImageIndex.h',
'libANGLE/ImageIndex.cpp', 'libANGLE/ImageIndex.cpp',
'libANGLE/IndexRangeCache.cpp', 'libANGLE/IndexRangeCache.cpp',
...@@ -136,6 +138,7 @@ ...@@ -136,6 +138,7 @@
'libANGLE/renderer/FenceNVImpl.h', 'libANGLE/renderer/FenceNVImpl.h',
'libANGLE/renderer/FenceSyncImpl.h', 'libANGLE/renderer/FenceSyncImpl.h',
'libANGLE/renderer/FramebufferImpl.h', 'libANGLE/renderer/FramebufferImpl.h',
'libANGLE/renderer/ImageImpl.h',
'libANGLE/renderer/ImplFactory.h', 'libANGLE/renderer/ImplFactory.h',
'libANGLE/renderer/ProgramImpl.cpp', 'libANGLE/renderer/ProgramImpl.cpp',
'libANGLE/renderer/ProgramImpl.h', 'libANGLE/renderer/ProgramImpl.h',
......
...@@ -1196,7 +1196,13 @@ ANGLE_EXPORT void GL_APIENTRY EGLImageTargetTexture2DOES(GLenum target, GLeglIma ...@@ -1196,7 +1196,13 @@ ANGLE_EXPORT void GL_APIENTRY EGLImageTargetTexture2DOES(GLenum target, GLeglIma
return; return;
} }
UNIMPLEMENTED(); Texture *texture = context->getTargetTexture(target);
Error error = texture->setEGLImageTarget(target, imageObject);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
...@@ -1215,7 +1221,13 @@ ANGLE_EXPORT void GL_APIENTRY EGLImageTargetRenderbufferStorageOES(GLenum target ...@@ -1215,7 +1221,13 @@ ANGLE_EXPORT void GL_APIENTRY EGLImageTargetRenderbufferStorageOES(GLenum target
return; return;
} }
UNIMPLEMENTED(); Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer();
Error error = renderbuffer->setStorageEGLImageTarget(imageObject);
if (error.isError())
{
context->recordError(error);
return;
}
} }
} }
} }
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
'<(angle_path)/src/tests/gl_tests/FramebufferFormatsTest.cpp', '<(angle_path)/src/tests/gl_tests/FramebufferFormatsTest.cpp',
'<(angle_path)/src/tests/gl_tests/FramebufferRenderMipmapTest.cpp', '<(angle_path)/src/tests/gl_tests/FramebufferRenderMipmapTest.cpp',
'<(angle_path)/src/tests/gl_tests/GLSLTest.cpp', '<(angle_path)/src/tests/gl_tests/GLSLTest.cpp',
'<(angle_path)/src/tests/gl_tests/ImageTest.cpp',
'<(angle_path)/src/tests/gl_tests/IncompleteTextureTest.cpp', '<(angle_path)/src/tests/gl_tests/IncompleteTextureTest.cpp',
'<(angle_path)/src/tests/gl_tests/IndexBufferOffsetTest.cpp', '<(angle_path)/src/tests/gl_tests/IndexBufferOffsetTest.cpp',
'<(angle_path)/src/tests/gl_tests/IndexedPointsTest.cpp', '<(angle_path)/src/tests/gl_tests/IndexedPointsTest.cpp',
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
'<(angle_path)/src/libANGLE/Config_unittest.cpp', '<(angle_path)/src/libANGLE/Config_unittest.cpp',
'<(angle_path)/src/libANGLE/Fence_unittest.cpp', '<(angle_path)/src/libANGLE/Fence_unittest.cpp',
'<(angle_path)/src/libANGLE/HandleAllocator_unittest.cpp', '<(angle_path)/src/libANGLE/HandleAllocator_unittest.cpp',
'<(angle_path)/src/libANGLE/Image_unittest.cpp',
'<(angle_path)/src/libANGLE/ImageIndexIterator_unittest.cpp', '<(angle_path)/src/libANGLE/ImageIndexIterator_unittest.cpp',
'<(angle_path)/src/libANGLE/Program_unittest.cpp', '<(angle_path)/src/libANGLE/Program_unittest.cpp',
'<(angle_path)/src/libANGLE/ResourceManager_unittest.cpp', '<(angle_path)/src/libANGLE/ResourceManager_unittest.cpp',
...@@ -31,6 +32,7 @@ ...@@ -31,6 +32,7 @@
'<(angle_path)/src/libANGLE/TransformFeedback_unittest.cpp', '<(angle_path)/src/libANGLE/TransformFeedback_unittest.cpp',
'<(angle_path)/src/libANGLE/renderer/BufferImpl_mock.h', '<(angle_path)/src/libANGLE/renderer/BufferImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/RenderbufferImpl_mock.h', '<(angle_path)/src/libANGLE/renderer/RenderbufferImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/ImageImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/TextureImpl_mock.h', '<(angle_path)/src/libANGLE/renderer/TextureImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/TransformFeedbackImpl_mock.h', '<(angle_path)/src/libANGLE/renderer/TransformFeedbackImpl_mock.h',
'<(angle_path)/src/tests/angle_unittests_utils.h', '<(angle_path)/src/tests/angle_unittests_utils.h',
......
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