Commit 701b74b0 by Ian Ewell

Add support for EGL_KHR_stream.

EGL_KHR_stream is now implemented. Since the extension does not come with any producers or consumers, it does not have much functionality and the implementation is therefore very simple (validation layers and a new object to store some attributes). This however add the groundwork to add the appropriate consumer and producer extensions to stream D3D NV12 textures directly into ANGLE which will significantly improve video performance on Chromium on D3D-based platforms. BUG=angleproject:1332 Change-Id: Ie240c73869f5098d1215cc5e27aa5decd06c3ed1 Reviewed-on: https://chromium-review.googlesource.com/330003 Commit-Queue: Ian Ewell <ewell@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent bb51c35c
...@@ -635,7 +635,8 @@ DisplayExtensions::DisplayExtensions() ...@@ -635,7 +635,8 @@ DisplayExtensions::DisplayExtensions()
getAllProcAddresses(false), getAllProcAddresses(false),
flexibleSurfaceCompatibility(false), flexibleSurfaceCompatibility(false),
directComposition(false), directComposition(false),
createContextNoError(false) createContextNoError(false),
stream(false)
{ {
} }
...@@ -664,6 +665,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const ...@@ -664,6 +665,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_KHR_gl_texture_3D_image", glTexture3DImage, &extensionStrings); InsertExtensionString("EGL_KHR_gl_texture_3D_image", glTexture3DImage, &extensionStrings);
InsertExtensionString("EGL_KHR_gl_renderbuffer_image", glRenderbufferImage, &extensionStrings); InsertExtensionString("EGL_KHR_gl_renderbuffer_image", glRenderbufferImage, &extensionStrings);
InsertExtensionString("EGL_KHR_get_all_proc_addresses", getAllProcAddresses, &extensionStrings); InsertExtensionString("EGL_KHR_get_all_proc_addresses", getAllProcAddresses, &extensionStrings);
InsertExtensionString("EGL_KHR_stream", stream, &extensionStrings);
InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility", flexibleSurfaceCompatibility, &extensionStrings); InsertExtensionString("EGL_ANGLE_flexible_surface_compatibility", flexibleSurfaceCompatibility, &extensionStrings);
// TODO(jmadill): Enable this when complete. // TODO(jmadill): Enable this when complete.
//InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings); //InsertExtensionString("KHR_create_context_no_error", createContextNoError, &extensionStrings);
......
...@@ -482,6 +482,9 @@ struct DisplayExtensions ...@@ -482,6 +482,9 @@ struct DisplayExtensions
// KHR_create_context_no_error // KHR_create_context_no_error
bool createContextNoError; bool createContextNoError;
// EGL_KHR_stream
bool stream;
}; };
struct DeviceExtensions struct DeviceExtensions
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "libANGLE/histogram_macros.h" #include "libANGLE/histogram_macros.h"
#include "libANGLE/Image.h" #include "libANGLE/Image.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include "libANGLE/Stream.h"
#include "libANGLE/renderer/DisplayImpl.h" #include "libANGLE/renderer/DisplayImpl.h"
#include "libANGLE/renderer/ImageImpl.h" #include "libANGLE/renderer/ImageImpl.h"
#include "third_party/trace_event/trace_event.h" #include "third_party/trace_event/trace_event.h"
...@@ -299,6 +300,7 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe ...@@ -299,6 +300,7 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe
mAttributeMap(), mAttributeMap(),
mConfigSet(), mConfigSet(),
mContextSet(), mContextSet(),
mStreamSet(),
mInitialized(false), mInitialized(false),
mCaps(), mCaps(),
mDisplayExtensions(), mDisplayExtensions(),
...@@ -438,6 +440,11 @@ void Display::terminate() ...@@ -438,6 +440,11 @@ void Display::terminate()
destroyImage(*mImageSet.begin()); destroyImage(*mImageSet.begin());
} }
while (!mStreamSet.empty())
{
destroyStream(*mStreamSet.begin());
}
while (!mImplementation->getSurfaceSet().empty()) while (!mImplementation->getSurfaceSet().empty())
{ {
destroySurface(*mImplementation->getSurfaceSet().begin()); destroySurface(*mImplementation->getSurfaceSet().begin());
...@@ -699,6 +706,24 @@ Error Display::createImage(gl::Context *context, ...@@ -699,6 +706,24 @@ Error Display::createImage(gl::Context *context,
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
} }
Error Display::createStream(const AttributeMap &attribs, Stream **outStream)
{
ASSERT(isInitialized());
rx::StreamImpl *streamImpl = mImplementation->createStream(attribs);
ASSERT(streamImpl != nullptr);
Stream *stream = new Stream(streamImpl, attribs);
ASSERT(stream != nullptr);
mStreamSet.insert(stream);
ASSERT(outStream != nullptr);
*outStream = stream;
return Error(EGL_SUCCESS);
}
Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, Error Display::createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs,
gl::Context **outContext) gl::Context **outContext)
{ {
...@@ -788,6 +813,12 @@ void Display::destroyImage(egl::Image *image) ...@@ -788,6 +813,12 @@ void Display::destroyImage(egl::Image *image)
mImageSet.erase(iter); mImageSet.erase(iter);
} }
void Display::destroyStream(egl::Stream *stream)
{
mStreamSet.erase(stream);
SafeDelete(stream);
}
void Display::destroyContext(gl::Context *context) void Display::destroyContext(gl::Context *context)
{ {
mContextSet.erase(context); mContextSet.erase(context);
...@@ -854,6 +885,11 @@ bool Display::isValidImage(const Image *image) const ...@@ -854,6 +885,11 @@ bool Display::isValidImage(const Image *image) const
return mImageSet.find(const_cast<Image *>(image)) != mImageSet.end(); return mImageSet.find(const_cast<Image *>(image)) != mImageSet.end();
} }
bool Display::isValidStream(const Stream *stream) const
{
return mStreamSet.find(const_cast<Stream *>(stream)) != mStreamSet.end();
}
bool Display::hasExistingWindowSurface(EGLNativeWindowType window) bool Display::hasExistingWindowSurface(EGLNativeWindowType window)
{ {
WindowSurfaceMap *windowSurfaces = GetWindowSurfaces(); WindowSurfaceMap *windowSurfaces = GetWindowSurfaces();
......
...@@ -35,6 +35,7 @@ namespace egl ...@@ -35,6 +35,7 @@ namespace egl
class Device; class Device;
class Image; class Image;
class Surface; class Surface;
class Stream;
class Display final : angle::NonCopyable class Display final : angle::NonCopyable
{ {
...@@ -67,6 +68,8 @@ class Display final : angle::NonCopyable ...@@ -67,6 +68,8 @@ class Display final : angle::NonCopyable
const AttributeMap &attribs, const AttributeMap &attribs,
Image **outImage); Image **outImage);
Error createStream(const AttributeMap &attribs, Stream **outStream);
Error createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs, Error createContext(const Config *configuration, gl::Context *shareContext, const AttributeMap &attribs,
gl::Context **outContext); gl::Context **outContext);
...@@ -74,6 +77,7 @@ class Display final : angle::NonCopyable ...@@ -74,6 +77,7 @@ class Display final : angle::NonCopyable
void destroySurface(egl::Surface *surface); void destroySurface(egl::Surface *surface);
void destroyImage(egl::Image *image); void destroyImage(egl::Image *image);
void destroyStream(egl::Stream *stream);
void destroyContext(gl::Context *context); void destroyContext(gl::Context *context);
bool isInitialized() const; bool isInitialized() const;
...@@ -81,6 +85,7 @@ class Display final : angle::NonCopyable ...@@ -81,6 +85,7 @@ class Display final : angle::NonCopyable
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 isValidImage(const Image *image) const;
bool isValidStream(const Stream *stream) 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);
...@@ -130,6 +135,9 @@ class Display final : angle::NonCopyable ...@@ -130,6 +135,9 @@ class Display final : angle::NonCopyable
typedef std::set<Image *> ImageSet; typedef std::set<Image *> ImageSet;
ImageSet mImageSet; ImageSet mImageSet;
typedef std::set<Stream *> StreamSet;
StreamSet mStreamSet;
bool mInitialized; bool mInitialized;
Caps mCaps; Caps mCaps;
......
//
// Copyright (c) 2016 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.
//
// Stream.cpp: Implements the egl::Stream class, representing the stream
// where frames are streamed in. Implements EGLStreanKHR.
#include "libANGLE/Stream.h"
#include <platform/Platform.h>
#include <EGL/eglext.h>
#include "common/debug.h"
#include "common/mathutil.h"
#include "common/platform.h"
#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/StreamImpl.h"
namespace egl
{
Stream::Stream(rx::StreamImpl *impl, const AttributeMap &attribs)
: mImplementation(impl),
mState(EGL_STREAM_STATE_CREATED_KHR),
mProducerFrame(0),
mConsumerFrame(0),
mConsumerLatency(attribs.get(EGL_CONSUMER_LATENCY_USEC_KHR, 0))
{
}
Stream::~Stream()
{
SafeDelete(mImplementation);
}
void Stream::setConsumerLatency(EGLint latency)
{
mConsumerLatency = latency;
}
EGLint Stream::getConsumerLatency() const
{
return mConsumerLatency;
}
EGLuint64KHR Stream::getProducerFrame() const
{
return mProducerFrame;
}
EGLuint64KHR Stream::getConsumerFrame() const
{
return mConsumerFrame;
}
EGLenum Stream::getState() const
{
return mState;
}
} // namespace egl
//
// Copyright (c) 2016 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.
//
// Stream.h: Defines the egl::Stream class, representing the stream
// where frames are streamed in. Implements EGLStreanKHR.
#ifndef LIBANGLE_STREAM_H_
#define LIBANGLE_STREAM_H_
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "common/angleutils.h"
#include "libANGLE/AttributeMap.h"
namespace rx
{
class StreamImpl;
}
namespace egl
{
class Stream final : angle::NonCopyable
{
public:
Stream(rx::StreamImpl *impl, const AttributeMap &attribs);
~Stream();
EGLenum getState() const;
void setConsumerLatency(EGLint latency);
EGLint getConsumerLatency() const;
EGLuint64KHR getProducerFrame() const;
EGLuint64KHR getConsumerFrame() const;
private:
// Implementation
rx::StreamImpl *mImplementation;
// EGL defined attributes
EGLint mState;
EGLuint64KHR mProducerFrame;
EGLuint64KHR mConsumerFrame;
EGLint mConsumerLatency;
};
} // namespace egl
#endif // LIBANGLE_STREAM_H_
...@@ -38,6 +38,7 @@ class SurfaceImpl; ...@@ -38,6 +38,7 @@ class SurfaceImpl;
class ImageImpl; class ImageImpl;
struct ConfigDesc; struct ConfigDesc;
class DeviceImpl; class DeviceImpl;
class StreamImpl;
class DisplayImpl : angle::NonCopyable class DisplayImpl : angle::NonCopyable
{ {
...@@ -68,6 +69,8 @@ class DisplayImpl : angle::NonCopyable ...@@ -68,6 +69,8 @@ class DisplayImpl : angle::NonCopyable
const gl::Context *shareContext, const gl::Context *shareContext,
const egl::AttributeMap &attribs) = 0; const egl::AttributeMap &attribs) = 0;
virtual StreamImpl *createStream(const egl::AttributeMap &attribs) = 0;
virtual egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) = 0; virtual egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) = 0;
virtual egl::ConfigSet generateConfigs() const = 0; virtual egl::ConfigSet generateConfigs() const = 0;
......
...@@ -30,6 +30,7 @@ class ShaderImpl; ...@@ -30,6 +30,7 @@ class ShaderImpl;
class TextureImpl; class TextureImpl;
class TransformFeedbackImpl; class TransformFeedbackImpl;
class VertexArrayImpl; class VertexArrayImpl;
class StreamImpl;
class ImplFactory : angle::NonCopyable class ImplFactory : angle::NonCopyable
{ {
......
//
// Copyright (c) 2016 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.
//
// StreamImpl.h: Defines the abstract rx::StreamImpl class.
#ifndef LIBANGLE_RENDERER_STREAMIMPL_H_
#define LIBANGLE_RENDERER_STREAMIMPL_H_
#include "common/angleutils.h"
namespace rx
{
class StreamImpl : angle::NonCopyable
{
public:
explicit StreamImpl() {}
virtual ~StreamImpl() {}
};
} // namespace rx
#endif // LIBANGLE_RENDERER_STREAMIMPL_H_
...@@ -237,6 +237,12 @@ gl::Context *DisplayD3D::createContext(const egl::Config *config, ...@@ -237,6 +237,12 @@ gl::Context *DisplayD3D::createContext(const egl::Config *config,
return new gl::Context(config, shareContext, mRenderer, attribs); return new gl::Context(config, shareContext, mRenderer, attribs);
} }
StreamImpl *DisplayD3D::createStream(const egl::AttributeMap &attribs)
{
ASSERT(mRenderer != nullptr);
return mRenderer->createStream(attribs);
}
egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) egl::Error DisplayD3D::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context)
{ {
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
......
...@@ -45,6 +45,8 @@ class DisplayD3D : public DisplayImpl ...@@ -45,6 +45,8 @@ class DisplayD3D : public DisplayImpl
const gl::Context *shareContext, const gl::Context *shareContext,
const egl::AttributeMap &attribs) override; const egl::AttributeMap &attribs) override;
StreamImpl *createStream(const egl::AttributeMap &attribs) override;
egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override; egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override;
egl::ConfigSet generateConfigs() const override; egl::ConfigSet generateConfigs() const override;
......
...@@ -265,6 +265,9 @@ class RendererD3D : public Renderer, public BufferFactoryD3D ...@@ -265,6 +265,9 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
bool presentPathFastEnabled() const { return mPresentPathFastEnabled; } bool presentPathFastEnabled() const { return mPresentPathFastEnabled; }
// Stream creation
virtual StreamImpl *createStream(const egl::AttributeMap &attribs) = 0;
protected: protected:
virtual bool getLUID(LUID *adapterLuid) const = 0; virtual bool getLUID(LUID *adapterLuid) const = 0;
virtual gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) = 0; virtual gl::Error applyShadersImpl(const gl::Data &data, GLenum drawMode) = 0;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h" #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
#include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h" #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
#include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h" #include "libANGLE/renderer/d3d/d3d11/ShaderExecutable11.h"
#include "libANGLE/renderer/d3d/d3d11/Stream11.h"
#include "libANGLE/renderer/d3d/d3d11/SwapChain11.h" #include "libANGLE/renderer/d3d/d3d11/SwapChain11.h"
#include "libANGLE/renderer/d3d/d3d11/texture_format_table.h" #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
#include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
...@@ -1027,6 +1028,8 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions ...@@ -1027,6 +1028,8 @@ void Renderer11::generateDisplayExtensions(egl::DisplayExtensions *outExtensions
outExtensions->glTextureCubemapImage = true; outExtensions->glTextureCubemapImage = true;
outExtensions->glRenderbufferImage = true; outExtensions->glRenderbufferImage = true;
outExtensions->stream = true;
outExtensions->flexibleSurfaceCompatibility = true; outExtensions->flexibleSurfaceCompatibility = true;
outExtensions->directComposition = !!mDCompModule; outExtensions->directComposition = !!mDCompModule;
} }
...@@ -3498,6 +3501,11 @@ TransformFeedbackImpl* Renderer11::createTransformFeedback() ...@@ -3498,6 +3501,11 @@ TransformFeedbackImpl* Renderer11::createTransformFeedback()
return new TransformFeedbackD3D(); return new TransformFeedbackD3D();
} }
StreamImpl *Renderer11::createStream(const egl::AttributeMap &attribs)
{
return new Stream11(this);
}
bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const
{ {
ASSERT(getRendererExtensions().pixelBufferObject); ASSERT(getRendererExtensions().pixelBufferObject);
......
...@@ -239,6 +239,9 @@ class Renderer11 : public RendererD3D ...@@ -239,6 +239,9 @@ class Renderer11 : public RendererD3D
// Transform Feedback creation // Transform Feedback creation
virtual TransformFeedbackImpl* createTransformFeedback(); virtual TransformFeedbackImpl* createTransformFeedback();
// Stream Creation
StreamImpl *createStream(const egl::AttributeMap &attribs) override;
// D3D11-renderer specific methods // D3D11-renderer specific methods
ID3D11Device *getDevice() { return mDevice; } ID3D11Device *getDevice() { return mDevice; }
void *getD3DDevice() override; void *getD3DDevice() override;
......
//
// Copyright (c) 2016 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.
//
// Stream11.cpp: Defines the rx::Stream11 class which implements rx::StreamImpl.
#include "libANGLE/renderer/d3d/d3d11/Stream11.h"
#include "common/utilities.h"
#include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
Stream11::Stream11(Renderer11 *renderer) : mRenderer(renderer)
{
}
Stream11::~Stream11()
{
}
} // namespace rx
//
// Copyright (c) 2016 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.
//
// Stream11.h: Defines the rx::Stream11 class which implements rx::StreamImpl.
#ifndef LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_
#define LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_
#include "libANGLE/renderer/StreamImpl.h"
namespace rx
{
class Renderer11;
class Stream11 : public StreamImpl
{
public:
Stream11(Renderer11 *renderer);
~Stream11() override;
private:
Renderer11 *mRenderer;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D11_STREAM11_H_
...@@ -770,6 +770,13 @@ TransformFeedbackImpl* Renderer9::createTransformFeedback() ...@@ -770,6 +770,13 @@ TransformFeedbackImpl* Renderer9::createTransformFeedback()
return new TransformFeedbackD3D(); return new TransformFeedbackD3D();
} }
StreamImpl *Renderer9::createStream(const egl::AttributeMap &attribs)
{
// Streams are not supported under D3D9
UNREACHABLE();
return nullptr;
}
bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const
{ {
// Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3.
......
...@@ -237,6 +237,9 @@ class Renderer9 : public RendererD3D ...@@ -237,6 +237,9 @@ class Renderer9 : public RendererD3D
// Transform Feedback creation // Transform Feedback creation
virtual TransformFeedbackImpl* createTransformFeedback(); virtual TransformFeedbackImpl* createTransformFeedback();
// Stream Creation
StreamImpl *createStream(const egl::AttributeMap &attribs) override;
// Buffer-to-texture and Texture-to-buffer copies // Buffer-to-texture and Texture-to-buffer copies
virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const;
virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget,
......
...@@ -63,6 +63,12 @@ gl::Context *DisplayGL::createContext(const egl::Config *config, ...@@ -63,6 +63,12 @@ gl::Context *DisplayGL::createContext(const egl::Config *config,
return new gl::Context(config, shareContext, mRenderer, attribs); return new gl::Context(config, shareContext, mRenderer, attribs);
} }
StreamImpl *DisplayGL::createStream(const egl::AttributeMap &attribs)
{
UNREACHABLE();
return nullptr;
}
egl::Error DisplayGL::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) egl::Error DisplayGL::makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context)
{ {
if (!drawSurface) if (!drawSurface)
......
...@@ -34,6 +34,8 @@ class DisplayGL : public DisplayImpl ...@@ -34,6 +34,8 @@ class DisplayGL : public DisplayImpl
const gl::Context *shareContext, const gl::Context *shareContext,
const egl::AttributeMap &attribs) override; const egl::AttributeMap &attribs) override;
StreamImpl *createStream(const egl::AttributeMap &attribs) override;
egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override; egl::Error makeCurrent(egl::Surface *drawSurface, egl::Surface *readSurface, gl::Context *context) override;
virtual egl::Error getDriverVersion(std::string *version) const = 0; virtual egl::Error getDriverVersion(std::string *version) const = 0;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "libANGLE/Device.h" #include "libANGLE/Device.h"
#include "libANGLE/Display.h" #include "libANGLE/Display.h"
#include "libANGLE/Image.h" #include "libANGLE/Image.h"
#include "libANGLE/Stream.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include <EGL/eglext.h> #include <EGL/eglext.h>
...@@ -176,6 +177,28 @@ Error ValidateImage(const Display *display, const Image *image) ...@@ -176,6 +177,28 @@ Error ValidateImage(const Display *display, const Image *image)
return Error(EGL_SUCCESS); return Error(EGL_SUCCESS);
} }
Error ValidateStream(const Display *display, const Stream *stream)
{
Error error = ValidateDisplay(display);
if (error.isError())
{
return error;
}
const DisplayExtensions &displayExtensions = display->getExtensions();
if (!displayExtensions.stream)
{
return Error(EGL_BAD_ACCESS, "Stream extension not active");
}
if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
{
return Error(EGL_BAD_STREAM_KHR, "Invalid stream");
}
return Error(GL_NO_ERROR);
}
Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext, Error ValidateCreateContext(Display *display, Config *configuration, gl::Context *shareContext,
const AttributeMap& attributes) const AttributeMap& attributes)
{ {
...@@ -1054,4 +1077,136 @@ Error ValidateReleaseDeviceANGLE(Device *device) ...@@ -1054,4 +1077,136 @@ Error ValidateReleaseDeviceANGLE(Device *device)
return Error(EGL_SUCCESS); return Error(EGL_SUCCESS);
} }
Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes)
{
Error error = ValidateDisplay(display);
if (error.isError())
{
return error;
}
const DisplayExtensions &displayExtensions = display->getExtensions();
if (!displayExtensions.stream)
{
return Error(EGL_BAD_ALLOC, "Stream extension not active");
}
for (const auto &attributeIter : attributes)
{
EGLint attribute = attributeIter.first;
EGLint value = attributeIter.second;
switch (attribute)
{
case EGL_STREAM_STATE_KHR:
case EGL_PRODUCER_FRAME_KHR:
case EGL_CONSUMER_FRAME_KHR:
return Error(EGL_BAD_ACCESS, "Attempt to initialize readonly parameter");
case EGL_CONSUMER_LATENCY_USEC_KHR:
// Technically not in spec but a latency < 0 makes no sense so we check it
if (value < 0)
{
return Error(EGL_BAD_PARAMETER, "Latency must be positive");
}
break;
default:
return Error(EGL_BAD_ATTRIBUTE, "Invalid stream attribute");
}
}
return Error(EGL_SUCCESS);
}
Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream)
{
Error error = ValidateStream(display, stream);
if (error.isError())
{
return error;
}
return Error(EGL_SUCCESS);
}
Error ValidateStreamAttribKHR(const Display *display,
const Stream *stream,
EGLint attribute,
EGLint value)
{
Error error = ValidateStream(display, stream);
if (error.isError())
{
return error;
}
if (stream->getState() == EGL_STREAM_STATE_DISCONNECTED_KHR)
{
return Error(EGL_BAD_STATE_KHR, "Bad stream state");
}
switch (attribute)
{
case EGL_STREAM_STATE_KHR:
case EGL_PRODUCER_FRAME_KHR:
case EGL_CONSUMER_FRAME_KHR:
return Error(EGL_BAD_ACCESS, "Attribute is read only");
case EGL_CONSUMER_LATENCY_USEC_KHR:
if (value < 0)
{
return Error(EGL_BAD_PARAMETER, "Stream consumer latency must be positive");
}
break;
default:
return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute");
}
return Error(EGL_SUCCESS);
}
Error ValidateQueryStreamKHR(const Display *display,
const Stream *stream,
EGLenum attribute,
EGLint *value)
{
Error error = ValidateStream(display, stream);
if (error.isError())
{
return error;
}
switch (attribute)
{
case EGL_STREAM_STATE_KHR:
case EGL_CONSUMER_LATENCY_USEC_KHR:
break;
default:
return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute");
}
return Error(EGL_SUCCESS);
}
Error ValidateQueryStreamu64KHR(const Display *display,
const Stream *stream,
EGLenum attribute,
EGLuint64KHR *value)
{
Error error = ValidateStream(display, stream);
if (error.isError())
{
return error;
}
switch (attribute)
{
case EGL_CONSUMER_FRAME_KHR:
case EGL_PRODUCER_FRAME_KHR:
break;
default:
return Error(EGL_BAD_ATTRIBUTE, "Invalid attribute");
}
return Error(EGL_SUCCESS);
}
} }
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h>
namespace gl namespace gl
{ {
...@@ -26,6 +27,7 @@ struct Config; ...@@ -26,6 +27,7 @@ struct Config;
class Device; class Device;
class Display; class Display;
class Image; class Image;
class Stream;
class Surface; class Surface;
// Object validation // Object validation
...@@ -58,6 +60,21 @@ Error ValidateCreateDeviceANGLE(EGLint device_type, ...@@ -58,6 +60,21 @@ Error ValidateCreateDeviceANGLE(EGLint device_type,
const EGLAttrib *attrib_list); const EGLAttrib *attrib_list);
Error ValidateReleaseDeviceANGLE(Device *device); Error ValidateReleaseDeviceANGLE(Device *device);
Error ValidateCreateStreamKHR(const Display *display, const AttributeMap &attributes);
Error ValidateDestroyStreamKHR(const Display *display, const Stream *stream);
Error ValidateStreamAttribKHR(const Display *display,
const Stream *stream,
EGLint attribute,
EGLint value);
Error ValidateQueryStreamKHR(const Display *display,
const Stream *stream,
EGLenum attribute,
EGLint *value);
Error ValidateQueryStreamu64KHR(const Display *display,
const Stream *stream,
EGLenum attribute,
EGLuint64KHR *value);
// Other validation // Other validation
Error ValidateCompatibleConfigs(const Display *display, Error ValidateCompatibleConfigs(const Display *display,
const Config *config1, const Config *config1,
......
...@@ -288,4 +288,37 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const cha ...@@ -288,4 +288,37 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const cha
return egl::GetProcAddress(procname); return egl::GetProcAddress(procname);
} }
EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list)
{
return egl::CreateStreamKHR(dpy, attrib_list);
}
EGLBoolean EGLAPIENTRY eglDestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream)
{
return egl::DestroyStreamKHR(dpy, stream);
}
EGLBoolean EGLAPIENTRY eglStreamAttribKHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint value)
{
return egl::StreamAttribKHR(dpy, stream, attribute, value);
}
EGLBoolean EGLAPIENTRY eglQueryStreamKHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint *value)
{
return egl::QueryStreamKHR(dpy, stream, attribute, value);
}
EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLuint64KHR *value)
{
return egl::QueryStreamu64KHR(dpy, stream, attribute, value);
}
} }
...@@ -46,6 +46,11 @@ EXPORTS ...@@ -46,6 +46,11 @@ EXPORTS
eglDestroyImageKHR @52 eglDestroyImageKHR @52
eglCreateDeviceANGLE @53 eglCreateDeviceANGLE @53
eglReleaseDeviceANGLE @54 eglReleaseDeviceANGLE @54
eglCreateStreamKHR @55
eglDestroyStreamKHR @56
eglStreamAttribKHR @57
eglQueryStreamKHR @58
eglQueryStreamu64KHR @59
; 1.5 entry points ; 1.5 entry points
eglCreateSync @38 eglCreateSync @38
......
...@@ -109,6 +109,8 @@ ...@@ -109,6 +109,8 @@
'libANGLE/Shader.h', 'libANGLE/Shader.h',
'libANGLE/State.cpp', 'libANGLE/State.cpp',
'libANGLE/State.h', 'libANGLE/State.h',
'libANGLE/Stream.cpp',
'libANGLE/Stream.h',
'libANGLE/Surface.cpp', 'libANGLE/Surface.cpp',
'libANGLE/Surface.h', 'libANGLE/Surface.h',
'libANGLE/Texture.cpp', 'libANGLE/Texture.cpp',
...@@ -151,6 +153,7 @@ ...@@ -151,6 +153,7 @@
'libANGLE/renderer/Renderer.h', 'libANGLE/renderer/Renderer.h',
'libANGLE/renderer/SamplerImpl.h', 'libANGLE/renderer/SamplerImpl.h',
'libANGLE/renderer/ShaderImpl.h', 'libANGLE/renderer/ShaderImpl.h',
'libANGLE/renderer/StreamImpl.h',
'libANGLE/renderer/SurfaceImpl.cpp', 'libANGLE/renderer/SurfaceImpl.cpp',
'libANGLE/renderer/SurfaceImpl.h', 'libANGLE/renderer/SurfaceImpl.h',
'libANGLE/renderer/TextureImpl.h', 'libANGLE/renderer/TextureImpl.h',
...@@ -378,6 +381,8 @@ ...@@ -378,6 +381,8 @@
'libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h', 'libANGLE/renderer/d3d/d3d11/shaders/compiled/swizzleui3dps.h',
'libANGLE/renderer/d3d/d3d11/StateManager11.cpp', 'libANGLE/renderer/d3d/d3d11/StateManager11.cpp',
'libANGLE/renderer/d3d/d3d11/StateManager11.h', 'libANGLE/renderer/d3d/d3d11/StateManager11.h',
'libANGLE/renderer/d3d/d3d11/Stream11.cpp',
'libANGLE/renderer/d3d/d3d11/Stream11.h',
'libANGLE/renderer/d3d/d3d11/SwapChain11.cpp', 'libANGLE/renderer/d3d/d3d11/SwapChain11.cpp',
'libANGLE/renderer/d3d/d3d11/SwapChain11.h', 'libANGLE/renderer/d3d/d3d11/SwapChain11.h',
'libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp', 'libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp',
......
...@@ -1642,6 +1642,13 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char * ...@@ -1642,6 +1642,13 @@ __eglMustCastToProperFunctionPointerType EGLAPIENTRY GetProcAddress(const char *
INSERT_PROC_ADDRESS(egl, CreateDeviceANGLE); INSERT_PROC_ADDRESS(egl, CreateDeviceANGLE);
INSERT_PROC_ADDRESS(egl, ReleaseDeviceANGLE); INSERT_PROC_ADDRESS(egl, ReleaseDeviceANGLE);
// EGL_KHR_stream
INSERT_PROC_ADDRESS(egl, CreateStreamKHR);
INSERT_PROC_ADDRESS(egl, DestroyStreamKHR);
INSERT_PROC_ADDRESS(egl, StreamAttribKHR);
INSERT_PROC_ADDRESS(egl, QueryStreamKHR);
INSERT_PROC_ADDRESS(egl, QueryStreamu64KHR);
#undef INSERT_PROC_ADDRESS #undef INSERT_PROC_ADDRESS
return map; return map;
}; };
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "libANGLE/Display.h" #include "libANGLE/Display.h"
#include "libANGLE/Device.h" #include "libANGLE/Device.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
#include "libANGLE/Stream.h"
#include "libANGLE/validationEGL.h" #include "libANGLE/validationEGL.h"
#include "common/debug.h" #include "common/debug.h"
...@@ -551,4 +552,150 @@ ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device) ...@@ -551,4 +552,150 @@ ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device)
return EGL_TRUE; return EGL_TRUE;
} }
// EGL_KHR_stream
EGLStreamKHR EGLAPIENTRY CreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list)
{
EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLAttrib* attrib_list = 0x%0.8p)", dpy, attrib_list);
Display *display = static_cast<Display *>(dpy);
AttributeMap attributes(attrib_list);
Error error = ValidateCreateStreamKHR(display, attributes);
if (error.isError())
{
SetGlobalError(error);
return EGL_NO_STREAM_KHR;
}
Stream *stream;
error = display->createStream(attributes, &stream);
if (error.isError())
{
SetGlobalError(error);
return EGL_NO_STREAM_KHR;
}
return static_cast<EGLStreamKHR>(stream);
}
EGLBoolean EGLAPIENTRY DestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream)
{
EVENT("(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR = 0x%0.8p)", dpy, stream);
Display *display = static_cast<Display *>(dpy);
Stream *streamObject = static_cast<Stream *>(stream);
Error error = ValidateDestroyStreamKHR(display, streamObject);
if (error.isError())
{
SetGlobalError(error);
return EGL_FALSE;
}
display->destroyStream(streamObject);
return EGL_TRUE;
}
EGLBoolean EGLAPIENTRY StreamAttribKHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint value)
{
EVENT(
"(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLenum attribute = 0x%X, "
"EGLint value = 0x%X)",
dpy, stream, attribute, value);
Display *display = static_cast<Display *>(dpy);
Stream *streamObject = static_cast<Stream *>(stream);
Error error = ValidateStreamAttribKHR(display, streamObject, attribute, value);
if (error.isError())
{
SetGlobalError(error);
return EGL_FALSE;
}
switch (attribute)
{
case EGL_CONSUMER_LATENCY_USEC_KHR:
streamObject->setConsumerLatency(value);
break;
default:
UNREACHABLE();
}
return EGL_TRUE;
}
EGLBoolean EGLAPIENTRY QueryStreamKHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint *value)
{
EVENT(
"(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLenum attribute = 0x%X, "
"EGLint value = 0x%0.8p)",
dpy, stream, attribute, value);
Display *display = static_cast<Display *>(dpy);
Stream *streamObject = static_cast<Stream *>(stream);
Error error = ValidateQueryStreamKHR(display, streamObject, attribute, value);
if (error.isError())
{
SetGlobalError(error);
return EGL_FALSE;
}
switch (attribute)
{
case EGL_STREAM_STATE_KHR:
*value = streamObject->getState();
break;
case EGL_CONSUMER_LATENCY_USEC_KHR:
*value = streamObject->getConsumerLatency();
break;
default:
UNREACHABLE();
}
return EGL_TRUE;
}
EGLBoolean EGLAPIENTRY QueryStreamu64KHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLuint64KHR *value)
{
EVENT(
"(EGLDisplay dpy = 0x%0.8p, EGLStreamKHR stream = 0x%0.8p, EGLenum attribute = 0x%X, "
"EGLuint64KHR value = 0x%0.8p)",
dpy, stream, attribute, value);
Display *display = static_cast<Display *>(dpy);
Stream *streamObject = static_cast<Stream *>(stream);
Error error = ValidateQueryStreamu64KHR(display, streamObject, attribute, value);
if (error.isError())
{
SetGlobalError(error);
return EGL_FALSE;
}
switch (attribute)
{
case EGL_PRODUCER_FRAME_KHR:
*value = streamObject->getProducerFrame();
break;
case EGL_CONSUMER_FRAME_KHR:
*value = streamObject->getConsumerFrame();
break;
default:
UNREACHABLE();
}
return EGL_TRUE;
}
} }
...@@ -43,6 +43,22 @@ ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type, ...@@ -43,6 +43,22 @@ ANGLE_EXPORT EGLDeviceEXT EGLAPIENTRY CreateDeviceANGLE(EGLint device_type,
void *native_device, void *native_device,
const EGLAttrib *attrib_list); const EGLAttrib *attrib_list);
ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device); ANGLE_EXPORT EGLBoolean EGLAPIENTRY ReleaseDeviceANGLE(EGLDeviceEXT device);
// EGL_KHR_stream
ANGLE_EXPORT EGLStreamKHR EGLAPIENTRY CreateStreamKHR(EGLDisplay dpy, const EGLint *attrib_list);
ANGLE_EXPORT EGLBoolean EGLAPIENTRY DestroyStreamKHR(EGLDisplay dpy, EGLStreamKHR stream);
ANGLE_EXPORT EGLBoolean EGLAPIENTRY StreamAttribKHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint value);
ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryStreamKHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLint *value);
ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryStreamu64KHR(EGLDisplay dpy,
EGLStreamKHR stream,
EGLenum attribute,
EGLuint64KHR *value);
} }
#endif // LIBGLESV2_ENTRYPOINTSEGLEXT_H_ #endif // LIBGLESV2_ENTRYPOINTSEGLEXT_H_
...@@ -85,6 +85,7 @@ ...@@ -85,6 +85,7 @@
'<(angle_path)/src/tests/gl_tests/D3D11InputLayoutCacheTest.cpp', '<(angle_path)/src/tests/gl_tests/D3D11InputLayoutCacheTest.cpp',
'<(angle_path)/src/tests/egl_tests/EGLDeviceTest.cpp', '<(angle_path)/src/tests/egl_tests/EGLDeviceTest.cpp',
'<(angle_path)/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp', '<(angle_path)/src/tests/egl_tests/EGLPresentPathD3D11Test.cpp',
'<(angle_path)/src/tests/egl_tests/EGLStreamTest.cpp',
# TODO(cwallez) for Linux, requires a portable implementation of threads # TODO(cwallez) for Linux, requires a portable implementation of threads
'<(angle_path)/src/tests/egl_tests/EGLThreadTest.cpp', '<(angle_path)/src/tests/egl_tests/EGLThreadTest.cpp',
], ],
......
//
// Copyright 2016 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.
//
// EGLStreamTest:
// Tests pertaining to egl::Stream.
//
#include <gtest/gtest.h>
#include <vector>
#include "OSWindow.h"
#include "test_utils/ANGLETest.h"
using namespace angle;
namespace
{
class EGLStreamTest : public ANGLETest
{
protected:
EGLStreamTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
setConfigDepthBits(24);
}
};
// Tests validation of the stream API
TEST_P(EGLStreamTest, StreamValidationTest)
{
EGLWindow *window = getEGLWindow();
const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (strstr(extensionsString, "EGL_KHR_stream") == nullptr)
{
std::cout << "Stream extension not supported" << std::endl;
return;
}
EGLDisplay display = window->getDisplay();
const EGLint streamAttributesBad[] = {
EGL_STREAM_STATE_KHR,
0,
EGL_NONE,
EGL_PRODUCER_FRAME_KHR,
0,
EGL_NONE,
EGL_CONSUMER_FRAME_KHR,
0,
EGL_NONE,
EGL_CONSUMER_LATENCY_USEC_KHR,
-1,
EGL_NONE,
EGL_RED_SIZE,
EGL_DONT_CARE,
EGL_NONE,
};
// Validate create stream attributes
EGLStreamKHR stream = eglCreateStreamKHR(display, &streamAttributesBad[0]);
ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
stream = eglCreateStreamKHR(display, &streamAttributesBad[3]);
ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
stream = eglCreateStreamKHR(display, &streamAttributesBad[6]);
ASSERT_EGL_ERROR(EGL_BAD_ACCESS);
ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
stream = eglCreateStreamKHR(display, &streamAttributesBad[9]);
ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
stream = eglCreateStreamKHR(display, &streamAttributesBad[12]);
ASSERT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
const EGLint streamAttributes[] = {
EGL_CONSUMER_LATENCY_USEC_KHR, 0, EGL_NONE,
};
stream = eglCreateStreamKHR(EGL_NO_DISPLAY, streamAttributes);
ASSERT_EGL_ERROR(EGL_BAD_DISPLAY);
ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
// Create an actual stream
stream = eglCreateStreamKHR(display, streamAttributes);
ASSERT_EGL_SUCCESS();
ASSERT_EQ(EGL_NO_STREAM_KHR, stream);
// Assert it is in the created state
EGLint state;
eglQueryStreamKHR(display, stream, EGL_STREAM_STATE_KHR, &state);
ASSERT_EGL_SUCCESS();
ASSERT_EQ(EGL_STREAM_STATE_CREATED_KHR, state);
// Test getting and setting the latency
EGLint latency = 10;
eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, latency);
ASSERT_EGL_SUCCESS();
eglQueryStreamKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, &latency);
ASSERT_EGL_SUCCESS();
ASSERT_EQ(10, latency);
eglStreamAttribKHR(display, stream, EGL_CONSUMER_LATENCY_USEC_KHR, -1);
ASSERT_EGL_ERROR(EGL_BAD_PARAMETER);
ASSERT_EQ(10, latency);
// Test the 64-bit queries
EGLuint64KHR value;
eglQueryStreamu64KHR(display, stream, EGL_CONSUMER_FRAME_KHR, &value);
ASSERT_EGL_SUCCESS();
eglQueryStreamu64KHR(display, stream, EGL_PRODUCER_FRAME_KHR, &value);
ASSERT_EGL_SUCCESS();
// Destroy the stream
eglDestroyStreamKHR(display, stream);
ASSERT_EGL_SUCCESS();
}
ANGLE_INSTANTIATE_TEST(EGLStreamTest,
ES2_D3D9(),
ES2_D3D11(),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL());
} // anonymous namespace
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