Commit fce1e2d1 by Jonah Ryan-Davis Committed by Commit Bot

Extend eglGetPlatformDisplay to allow feature overrides.

Add EGL_FEATURE_OVERRIDES_ENABLED_ANGLE and EGL_FEATURE_OVERRIDES_DISABLED_ANGLE to submit lists of strings naming the features that should be overridden (either enabled or disabled) on display creation. Bug: angleproject:1621 Change-Id: I4bb75c5dbab0e3b701a72069c38f8c60ecfffad2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1646595 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 2589cdcc
...@@ -28,11 +28,11 @@ Number ...@@ -28,11 +28,11 @@ Number
Extension Type Extension Type
EGL device extension EGL client extension
Dependencies Dependencies
This extension is written against the wording of the EGL 1.4 This extension is written against the wording of the EGL 1.5
Specification. Specification.
EGL_EXT_device_query affects the definition of this extension. EGL_EXT_device_query affects the definition of this extension.
...@@ -73,12 +73,30 @@ New Tokens ...@@ -73,12 +73,30 @@ New Tokens
EGL_FEATURE_CATEGORY_ANGLE 0x3461 EGL_FEATURE_CATEGORY_ANGLE 0x3461
EGL_FEATURE_DESCRIPTION_ANGLE 0x3462 EGL_FEATURE_DESCRIPTION_ANGLE 0x3462
EGL_FEATURE_BUG_ANGLE 0x3463 EGL_FEATURE_BUG_ANGLE 0x3463
EGL_FEATURE_STATUS_ANGLE 0x3464 EGL_FEATURE_STATUS_ANGLE 0x3464
Accepted as a queried <attribute> in eglQueryDisplayAttribANGLE Accepted as a queried <attribute> in eglQueryDisplayAttribANGLE
EGL_FEATURE_COUNT_ANGLE 0x3465 EGL_FEATURE_COUNT_ANGLE 0x3465
Accepted as an attribute name in the <attrib_list> argument of
eglGetPlatformDisplay
EGL_FEATURE_OVERRIDES_ENABLED_ANGLE 0x3466
EGL_FEATURE_OVERRIDES_DISABLED_ANGLE 0x3467
New Behavior
The attribute following EGL_FEATURE_OVERRIDES_ENABLED_ANGLE or
EGL_FEATURE_OVERRIDES_DISABLED_ANGLE should be of type char**,
which should contain an array of strings naming the features to
be enabled or disabled upon display creation. Any features
unspecified by these arrays will be initialized with an internal
heuristic. Any features specified in one of the arrays will be
initialized to "enabled" or "disabled" dependent on in which
array it can be found. Any features specified in both arrays
will be initialized with undefined behavior.
Add the following to the end of section 3.3 "EGL Queries": Add the following to the end of section 3.3 "EGL Queries":
const char *eglQueryStringiANGLE(EGLDisplay dpy, const char *eglQueryStringiANGLE(EGLDisplay dpy,
......
...@@ -217,6 +217,8 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncValuesCHROMIUM(EGLDisplay dpy, ...@@ -217,6 +217,8 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncValuesCHROMIUM(EGLDisplay dpy,
#define EGL_FEATURE_BUG_ANGLE 0x3463 #define EGL_FEATURE_BUG_ANGLE 0x3463
#define EGL_FEATURE_STATUS_ANGLE 0x3464 #define EGL_FEATURE_STATUS_ANGLE 0x3464
#define EGL_FEATURE_COUNT_ANGLE 0x3465 #define EGL_FEATURE_COUNT_ANGLE 0x3465
#define EGL_FEATURE_OVERRIDES_ENABLED_ANGLE 0x3466
#define EGL_FEATURE_OVERRIDES_DISABLED_ANGLE 0x3467
typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGIANGLEPROC) (EGLDisplay dpy, EGLint name, EGLint index); typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGIANGLEPROC) (EGLDisplay dpy, EGLint name, EGLint index);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBANGLEPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value); typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBANGLEPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
#ifdef EGL_EGLEXT_PROTOTYPES #ifdef EGL_EGLEXT_PROTOTYPES
......
...@@ -143,11 +143,14 @@ struct FeatureSetBase ...@@ -143,11 +143,14 @@ struct FeatureSetBase
FeatureMap members = FeatureMap(); FeatureMap members = FeatureMap();
public: public:
void forceFeatureEnabled(const std::string &name, const bool enabled) void overrideFeatures(const std::vector<std::string> &feature_names, const bool enabled)
{ {
if (members.find(name) != members.end()) for (const std::string &name : feature_names)
{ {
members[name]->enabled = enabled; if (members.find(name) != members.end())
{
members[name]->enabled = enabled;
}
} }
} }
......
...@@ -1409,8 +1409,7 @@ DisplayExtensions::DisplayExtensions() ...@@ -1409,8 +1409,7 @@ DisplayExtensions::DisplayExtensions()
imageNativeBuffer(false), imageNativeBuffer(false),
getFrameTimestamps(false), getFrameTimestamps(false),
recordable(false), recordable(false),
powerPreference(false), powerPreference(false)
featureControlANGLE(false)
{} {}
std::vector<std::string> DisplayExtensions::getStrings() const std::vector<std::string> DisplayExtensions::getStrings() const
...@@ -1465,7 +1464,6 @@ std::vector<std::string> DisplayExtensions::getStrings() const ...@@ -1465,7 +1464,6 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_ANDROID_get_frame_timestamps", getFrameTimestamps, &extensionStrings); InsertExtensionString("EGL_ANDROID_get_frame_timestamps", getFrameTimestamps, &extensionStrings);
InsertExtensionString("EGL_ANDROID_recordable", recordable, &extensionStrings); InsertExtensionString("EGL_ANDROID_recordable", recordable, &extensionStrings);
InsertExtensionString("EGL_ANGLE_power_preference", powerPreference, &extensionStrings); InsertExtensionString("EGL_ANGLE_power_preference", powerPreference, &extensionStrings);
InsertExtensionString("EGL_ANGLE_feature_control", featureControlANGLE, &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);
// clang-format on // clang-format on
...@@ -1502,7 +1500,8 @@ ClientExtensions::ClientExtensions() ...@@ -1502,7 +1500,8 @@ ClientExtensions::ClientExtensions()
experimentalPresentPath(false), experimentalPresentPath(false),
clientGetAllProcAddresses(false), clientGetAllProcAddresses(false),
debug(false), debug(false),
explicitContext(false) explicitContext(false),
featureControlANGLE(false)
{} {}
ClientExtensions::ClientExtensions(const ClientExtensions &other) = default; ClientExtensions::ClientExtensions(const ClientExtensions &other) = default;
...@@ -1529,6 +1528,7 @@ std::vector<std::string> ClientExtensions::getStrings() const ...@@ -1529,6 +1528,7 @@ std::vector<std::string> ClientExtensions::getStrings() const
InsertExtensionString("EGL_KHR_client_get_all_proc_addresses", clientGetAllProcAddresses, &extensionStrings); InsertExtensionString("EGL_KHR_client_get_all_proc_addresses", clientGetAllProcAddresses, &extensionStrings);
InsertExtensionString("EGL_KHR_debug", debug, &extensionStrings); InsertExtensionString("EGL_KHR_debug", debug, &extensionStrings);
InsertExtensionString("EGL_ANGLE_explicit_context", explicitContext, &extensionStrings); InsertExtensionString("EGL_ANGLE_explicit_context", explicitContext, &extensionStrings);
InsertExtensionString("EGL_ANGLE_feature_control", featureControlANGLE, &extensionStrings);
// clang-format on // clang-format on
return extensionStrings; return extensionStrings;
......
...@@ -883,9 +883,6 @@ struct DisplayExtensions ...@@ -883,9 +883,6 @@ struct DisplayExtensions
// EGL_ANGLE_power_preference // EGL_ANGLE_power_preference
bool powerPreference; bool powerPreference;
// EGL_ANGLE_feature_control
bool featureControlANGLE;
}; };
struct DeviceExtensions struct DeviceExtensions
...@@ -954,6 +951,9 @@ struct ClientExtensions ...@@ -954,6 +951,9 @@ struct ClientExtensions
// EGL_ANGLE_explicit_context // EGL_ANGLE_explicit_context
bool explicitContext; bool explicitContext;
// EGL_ANGLE_feature_control
bool featureControlANGLE;
}; };
} // namespace egl } // namespace egl
......
...@@ -309,6 +309,19 @@ void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage) ...@@ -309,6 +309,19 @@ void Display_logInfo(angle::PlatformMethods *platform, const char *infoMessage)
gl::Trace(gl::LOG_INFO, infoMessage); gl::Trace(gl::LOG_INFO, infoMessage);
} }
const std::vector<std::string> EGLStringArrayToStringVector(const char **ary)
{
std::vector<std::string> vec;
if (ary != nullptr)
{
for (; *ary != nullptr; ary++)
{
vec.push_back(std::string(*ary));
}
}
return vec;
}
void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display) void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)
{ {
angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent(); angle::PlatformMethods *platformMethods = ANGLEPlatformCurrent();
...@@ -431,7 +444,8 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe ...@@ -431,7 +444,8 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe
mTextureManager(nullptr), mTextureManager(nullptr),
mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes), mBlobCache(gl::kDefaultMaxProgramCacheMemoryBytes),
mMemoryProgramCache(mBlobCache), mMemoryProgramCache(mBlobCache),
mGlobalTextureShareGroupUsers(0) mGlobalTextureShareGroupUsers(0),
mFeatures()
{} {}
Display::~Display() Display::~Display()
...@@ -498,6 +512,13 @@ void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap ...@@ -498,6 +512,13 @@ void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap
{ {
ANGLESetDefaultDisplayPlatform(this); ANGLESetDefaultDisplayPlatform(this);
} }
const char **featuresForceEnabled =
reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0));
const char **featuresForceDisabled =
reinterpret_cast<const char **>(mAttributeMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0));
mState.featureOverridesEnabled = EGLStringArrayToStringVector(featuresForceEnabled);
mState.featureOverridesDisabled = EGLStringArrayToStringVector(featuresForceDisabled);
} }
Error Display::initialize() Error Display::initialize()
...@@ -1189,6 +1210,7 @@ static ClientExtensions GenerateClientExtensions() ...@@ -1189,6 +1210,7 @@ static ClientExtensions GenerateClientExtensions()
extensions.clientGetAllProcAddresses = true; extensions.clientGetAllProcAddresses = true;
extensions.debug = true; extensions.debug = true;
extensions.explicitContext = true; extensions.explicitContext = true;
extensions.featureControlANGLE = true;
return extensions; return extensions;
} }
...@@ -1247,9 +1269,6 @@ void Display::initDisplayExtensions() ...@@ -1247,9 +1269,6 @@ void Display::initDisplayExtensions()
// that ANativeWindow is not recordable. // that ANativeWindow is not recordable.
mDisplayExtensions.recordable = true; mDisplayExtensions.recordable = true;
// EGL_ANGLE_feature_control is implemented on all backends.
mDisplayExtensions.featureControlANGLE = true;
mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions); mDisplayExtensionString = GenerateExtensionsString(mDisplayExtensions);
} }
......
...@@ -54,6 +54,8 @@ struct DisplayState final : private angle::NonCopyable ...@@ -54,6 +54,8 @@ struct DisplayState final : private angle::NonCopyable
EGLLabelKHR label; EGLLabelKHR label;
SurfaceSet surfaceSet; SurfaceSet surfaceSet;
std::vector<std::string> featureOverridesEnabled;
std::vector<std::string> featureOverridesDisabled;
}; };
// Constant coded here as a sanity limit. // Constant coded here as a sanity limit.
......
...@@ -92,6 +92,8 @@ class DisplayImpl : public EGLImplFactory ...@@ -92,6 +92,8 @@ class DisplayImpl : public EGLImplFactory
virtual void populateFeatureList(angle::FeatureList *features) = 0; virtual void populateFeatureList(angle::FeatureList *features) = 0;
const egl::DisplayState &getState() const { return mState; }
protected: protected:
const egl::DisplayState &mState; const egl::DisplayState &mState;
......
...@@ -184,6 +184,17 @@ angle::Result RendererD3D::initRenderTarget(const gl::Context *context, ...@@ -184,6 +184,17 @@ angle::Result RendererD3D::initRenderTarget(const gl::Context *context,
return clearRenderTarget(context, renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0); return clearRenderTarget(context, renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0);
} }
const angle::WorkaroundsD3D &RendererD3D::getWorkarounds() const
{
if (!mWorkaroundsInitialized)
{
generateWorkarounds(&mWorkarounds);
mWorkaroundsInitialized = true;
}
return mWorkarounds;
}
unsigned int GetBlendSampleMask(const gl::State &glState, int samples) unsigned int GetBlendSampleMask(const gl::State &glState, int samples)
{ {
unsigned int mask = 0; unsigned int mask = 0;
......
...@@ -2172,17 +2172,6 @@ std::string Renderer11::getShaderModelSuffix() const ...@@ -2172,17 +2172,6 @@ std::string Renderer11::getShaderModelSuffix() const
} }
} }
const angle::WorkaroundsD3D &RendererD3D::getWorkarounds() const
{
if (!mWorkaroundsInitialized)
{
generateWorkarounds(&mWorkarounds);
mWorkaroundsInitialized = true;
}
return mWorkarounds;
}
angle::Result Renderer11::copyImageInternal(const gl::Context *context, angle::Result Renderer11::copyImageInternal(const gl::Context *context,
const gl::Framebuffer *framebuffer, const gl::Framebuffer *framebuffer,
const gl::Rectangle &sourceRect, const gl::Rectangle &sourceRect,
...@@ -3692,6 +3681,7 @@ void Renderer11::generateCaps(gl::Caps *outCaps, ...@@ -3692,6 +3681,7 @@ void Renderer11::generateCaps(gl::Caps *outCaps,
void Renderer11::generateWorkarounds(angle::WorkaroundsD3D *workarounds) const void Renderer11::generateWorkarounds(angle::WorkaroundsD3D *workarounds) const
{ {
d3d11::GenerateWorkarounds(mRenderer11DeviceCaps, mAdapterDescription, workarounds); d3d11::GenerateWorkarounds(mRenderer11DeviceCaps, mAdapterDescription, workarounds);
OverrideFeaturesWithDisplayState(workarounds, mDisplay->getState());
} }
DeviceImpl *Renderer11::createEGLDevice() DeviceImpl *Renderer11::createEGLDevice()
......
...@@ -2977,6 +2977,7 @@ void Renderer9::generateCaps(gl::Caps *outCaps, ...@@ -2977,6 +2977,7 @@ void Renderer9::generateCaps(gl::Caps *outCaps,
void Renderer9::generateWorkarounds(angle::WorkaroundsD3D *workarounds) const void Renderer9::generateWorkarounds(angle::WorkaroundsD3D *workarounds) const
{ {
d3d9::GenerateWorkarounds(workarounds); d3d9::GenerateWorkarounds(workarounds);
OverrideFeaturesWithDisplayState(workarounds, mDisplay->getState());
} }
DeviceImpl *Renderer9::createEGLDevice() DeviceImpl *Renderer9::createEGLDevice()
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/AttributeMap.h" #include "libANGLE/AttributeMap.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/Path.h" #include "libANGLE/Path.h"
#include "libANGLE/State.h" #include "libANGLE/State.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
#include "libANGLE/renderer/gl/ClearMultiviewGL.h" #include "libANGLE/renderer/gl/ClearMultiviewGL.h"
#include "libANGLE/renderer/gl/CompilerGL.h" #include "libANGLE/renderer/gl/CompilerGL.h"
#include "libANGLE/renderer/gl/ContextGL.h" #include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/renderer/gl/DisplayGL.h"
#include "libANGLE/renderer/gl/FenceNVGL.h" #include "libANGLE/renderer/gl/FenceNVGL.h"
#include "libANGLE/renderer/gl/FramebufferGL.h" #include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h"
...@@ -180,7 +182,9 @@ static void INTERNAL_GL_APIENTRY LogGLDebugMessage(GLenum source, ...@@ -180,7 +182,9 @@ static void INTERNAL_GL_APIENTRY LogGLDebugMessage(GLenum source,
namespace rx namespace rx
{ {
RendererGL::RendererGL(std::unique_ptr<FunctionsGL> functions, const egl::AttributeMap &attribMap) RendererGL::RendererGL(std::unique_ptr<FunctionsGL> functions,
const egl::AttributeMap &attribMap,
DisplayGL *display)
: mMaxSupportedESVersion(0, 0), : mMaxSupportedESVersion(0, 0),
mFunctions(std::move(functions)), mFunctions(std::move(functions)),
mStateManager(nullptr), mStateManager(nullptr),
...@@ -193,8 +197,9 @@ RendererGL::RendererGL(std::unique_ptr<FunctionsGL> functions, const egl::Attrib ...@@ -193,8 +197,9 @@ RendererGL::RendererGL(std::unique_ptr<FunctionsGL> functions, const egl::Attrib
{ {
ASSERT(mFunctions); ASSERT(mFunctions);
nativegl_gl::GenerateWorkarounds(mFunctions.get(), &mWorkarounds); nativegl_gl::GenerateWorkarounds(mFunctions.get(), &mWorkarounds);
OverrideFeaturesWithDisplayState(&mWorkarounds, display->getState());
mStateManager = new StateManagerGL(mFunctions.get(), getNativeCaps(), getNativeExtensions()); mStateManager = new StateManagerGL(mFunctions.get(), getNativeCaps(), getNativeExtensions());
mBlitter = new BlitGL(mFunctions.get(), mWorkarounds, mStateManager); mBlitter = new BlitGL(mFunctions.get(), mWorkarounds, mStateManager);
mMultiviewClearer = new ClearMultiviewGL(mFunctions.get(), mStateManager); mMultiviewClearer = new ClearMultiviewGL(mFunctions.get(), mStateManager);
bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) || bool hasDebugOutput = mFunctions->isAtLeastGL(gl::Version(4, 3)) ||
......
...@@ -42,6 +42,7 @@ namespace rx ...@@ -42,6 +42,7 @@ namespace rx
class BlitGL; class BlitGL;
class ClearMultiviewGL; class ClearMultiviewGL;
class ContextImpl; class ContextImpl;
class DisplayGL;
class FunctionsGL; class FunctionsGL;
class RendererGL; class RendererGL;
class StateManagerGL; class StateManagerGL;
...@@ -73,7 +74,9 @@ class ScopedWorkerContextGL ...@@ -73,7 +74,9 @@ class ScopedWorkerContextGL
class RendererGL : angle::NonCopyable class RendererGL : angle::NonCopyable
{ {
public: public:
RendererGL(std::unique_ptr<FunctionsGL> functions, const egl::AttributeMap &attribMap); RendererGL(std::unique_ptr<FunctionsGL> functions,
const egl::AttributeMap &attribMap,
DisplayGL *display);
virtual ~RendererGL(); virtual ~RendererGL();
angle::Result flush(); angle::Result flush();
...@@ -205,8 +208,6 @@ class RendererGL : angle::NonCopyable ...@@ -205,8 +208,6 @@ class RendererGL : angle::NonCopyable
BlitGL *mBlitter; BlitGL *mBlitter;
ClearMultiviewGL *mMultiviewClearer; ClearMultiviewGL *mMultiviewClearer;
WorkaroundsGL mWorkarounds;
bool mUseDebugOutput; bool mUseDebugOutput;
mutable bool mCapsInitialized; mutable bool mCapsInitialized;
...@@ -224,6 +225,8 @@ class RendererGL : angle::NonCopyable ...@@ -224,6 +225,8 @@ class RendererGL : angle::NonCopyable
std::mutex mWorkerMutex; std::mutex mWorkerMutex;
bool mNativeParallelCompileEnabled; bool mNativeParallelCompileEnabled;
WorkaroundsGL mWorkarounds;
}; };
} // namespace rx } // namespace rx
......
...@@ -16,7 +16,7 @@ namespace rx ...@@ -16,7 +16,7 @@ namespace rx
RendererCGL::RendererCGL(std::unique_ptr<FunctionsGL> functions, RendererCGL::RendererCGL(std::unique_ptr<FunctionsGL> functions,
const egl::AttributeMap &attribMap, const egl::AttributeMap &attribMap,
DisplayCGL *display) DisplayCGL *display)
: RendererGL(std::move(functions), attribMap), mDisplay(display) : RendererGL(std::move(functions), attribMap, display), mDisplay(display)
{} {}
RendererCGL::~RendererCGL() {} RendererCGL::~RendererCGL() {}
......
...@@ -16,7 +16,7 @@ RendererEGL::RendererEGL(std::unique_ptr<FunctionsGL> functionsGL, ...@@ -16,7 +16,7 @@ RendererEGL::RendererEGL(std::unique_ptr<FunctionsGL> functionsGL,
DisplayEGL *display, DisplayEGL *display,
EGLContext context, EGLContext context,
const native_egl::AttributeVector attribs) const native_egl::AttributeVector attribs)
: RendererGL(std::move(functionsGL), attribMap), : RendererGL(std::move(functionsGL), attribMap, display),
mDisplay(display), mDisplay(display),
mContext(context), mContext(context),
mAttribs(attribs) mAttribs(attribs)
......
...@@ -16,7 +16,7 @@ namespace rx ...@@ -16,7 +16,7 @@ namespace rx
RendererGLX::RendererGLX(std::unique_ptr<FunctionsGL> functions, RendererGLX::RendererGLX(std::unique_ptr<FunctionsGL> functions,
const egl::AttributeMap &attribMap, const egl::AttributeMap &attribMap,
DisplayGLX *display) DisplayGLX *display)
: RendererGL(std::move(functions), attribMap), mDisplay(display) : RendererGL(std::move(functions), attribMap, display), mDisplay(display)
{} {}
RendererGLX::~RendererGLX() {} RendererGLX::~RendererGLX() {}
......
...@@ -17,7 +17,7 @@ RendererWGL::RendererWGL(std::unique_ptr<FunctionsGL> functionsGL, ...@@ -17,7 +17,7 @@ RendererWGL::RendererWGL(std::unique_ptr<FunctionsGL> functionsGL,
HGLRC context, HGLRC context,
HGLRC sharedContext, HGLRC sharedContext,
const std::vector<int> workerContextAttribs) const std::vector<int> workerContextAttribs)
: RendererGL(std::move(functionsGL), attribMap), : RendererGL(std::move(functionsGL), attribMap, display),
mDisplay(display), mDisplay(display),
mContext(context), mContext(context),
mSharedContext(sharedContext), mSharedContext(sharedContext),
......
...@@ -14,10 +14,13 @@ ...@@ -14,10 +14,13 @@
#include "libANGLE/AttributeMap.h" #include "libANGLE/AttributeMap.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ContextImpl.h" #include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/Format.h" #include "libANGLE/renderer/Format.h"
#include "platform/Feature.h"
#include <string.h> #include <string.h>
#include "common/utilities.h" #include "common/utilities.h"
...@@ -650,4 +653,11 @@ gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &r ...@@ -650,4 +653,11 @@ gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &r
// possible optimizations. // possible optimizations.
return rect; return rect;
} }
void OverrideFeaturesWithDisplayState(angle::FeatureSetBase *features,
const egl::DisplayState &state)
{
features->overrideFeatures(state.featureOverridesEnabled, true);
features->overrideFeatures(state.featureOverridesDisabled, false);
}
} // namespace rx } // namespace rx
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
namespace angle namespace angle
{ {
struct FeatureSetBase;
struct Format; struct Format;
enum class FormatID; enum class FormatID;
} // namespace angle } // namespace angle
...@@ -35,6 +36,7 @@ class State; ...@@ -35,6 +36,7 @@ class State;
namespace egl namespace egl
{ {
class AttributeMap; class AttributeMap;
struct DisplayState;
} // namespace egl } // namespace egl
namespace rx namespace rx
...@@ -301,6 +303,10 @@ angle::Result GetVertexRangeInfo(const gl::Context *context, ...@@ -301,6 +303,10 @@ angle::Result GetVertexRangeInfo(const gl::Context *context,
size_t *vertexCountOut); size_t *vertexCountOut);
gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY); gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY);
// Helper method to intialize a FeatureSet with overrides from the DisplayState
void OverrideFeaturesWithDisplayState(angle::FeatureSetBase *features,
const egl::DisplayState &state);
} // namespace rx } // namespace rx
#endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_ #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
...@@ -889,6 +889,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -889,6 +889,7 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
initFeatures(deviceExtensionNames); initFeatures(deviceExtensionNames);
OverrideFeaturesWithDisplayState(&mFeatures, displayVk->getState());
mFeaturesInitialized = true; mFeaturesInitialized = true;
// Selectively enable KHR_MAINTENANCE1 to support viewport flipping. // Selectively enable KHR_MAINTENANCE1 to support viewport flipping.
......
...@@ -599,6 +599,31 @@ Error ValidateGetPlatformDisplayCommon(EGLenum platform, ...@@ -599,6 +599,31 @@ Error ValidateGetPlatformDisplayCommon(EGLenum platform,
UNREACHABLE(); UNREACHABLE();
} }
if (attribMap.contains(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE))
{
if (!clientExtensions.featureControlANGLE)
{
return EglBadAttribute() << "EGL_ANGLE_feature_control is not supported";
}
else if (attribMap.get(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE, 0) == 0)
{
return EglBadAttribute()
<< "EGL_FEATURE_OVERRIDES_ENABLED_ANGLE must be a valid pointer";
}
}
if (attribMap.contains(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE))
{
if (!clientExtensions.featureControlANGLE)
{
return EglBadAttribute() << "EGL_ANGLE_feature_control is not supported";
}
else if (attribMap.get(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE, 0) == 0)
{
return EglBadAttribute()
<< "EGL_FEATURE_OVERRIDES_DISABLED_ANGLE must be a valid pointer";
}
}
return NoError(); return NoError();
} }
...@@ -3732,7 +3757,7 @@ Error ValidateQueryStringiANGLE(const Display *display, EGLint name, EGLint inde ...@@ -3732,7 +3757,7 @@ Error ValidateQueryStringiANGLE(const Display *display, EGLint name, EGLint inde
{ {
ANGLE_TRY(ValidateDisplay(display)); ANGLE_TRY(ValidateDisplay(display));
if (!display->getExtensions().featureControlANGLE) if (!Display::GetClientExtensions().featureControlANGLE)
{ {
return EglBadDisplay() << "EGL_ANGLE_feature_control extension is not available."; return EglBadDisplay() << "EGL_ANGLE_feature_control extension is not available.";
} }
...@@ -3776,7 +3801,7 @@ Error ValidateQueryDisplayAttribBase(const Display *display, const EGLint attrib ...@@ -3776,7 +3801,7 @@ Error ValidateQueryDisplayAttribBase(const Display *display, const EGLint attrib
break; break;
case EGL_FEATURE_COUNT_ANGLE: case EGL_FEATURE_COUNT_ANGLE:
if (!display->getExtensions().featureControlANGLE) if (!Display::GetClientExtensions().featureControlANGLE)
{ {
return EglBadDisplay() << "EGL_ANGLE_feature_control extension is not available."; return EglBadDisplay() << "EGL_ANGLE_feature_control extension is not available.";
} }
......
...@@ -18,16 +18,42 @@ class EGLFeatureControlTest : public ANGLETest ...@@ -18,16 +18,42 @@ class EGLFeatureControlTest : public ANGLETest
public: public:
void testSetUp() override void testSetUp() override
{ {
ASSERT_TRUE(IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
"EGL_ANGLE_feature_control"));
} }
void testTearDown() override {} void testTearDown() override
{
if (mDisplay != EGL_NO_DISPLAY)
{
eglTerminate(mDisplay);
}
}
protected:
EGLDisplay mDisplay;
bool initTest()
{
EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
if (mDisplay == EGL_NO_DISPLAY)
return false;
if (eglInitialize(mDisplay, nullptr, nullptr) != EGL_TRUE)
return false;
if (!IsEGLClientExtensionEnabled("EGL_ANGLE_feature_control"))
return false;
return true;
}
}; };
// Ensure eglQueryStringiANGLE generates EGL_BAD_DISPLAY if the display passed in is invalid. // Ensure eglQueryStringiANGLE generates EGL_BAD_DISPLAY if the display passed in is invalid.
TEST_P(EGLFeatureControlTest, InvalidDisplay) TEST_P(EGLFeatureControlTest, InvalidDisplay)
{ {
ASSERT_TRUE(initTest());
EXPECT_EQ(nullptr, eglQueryStringiANGLE(EGL_NO_DISPLAY, EGL_FEATURE_NAME_ANGLE, 0)); EXPECT_EQ(nullptr, eglQueryStringiANGLE(EGL_NO_DISPLAY, EGL_FEATURE_NAME_ANGLE, 0));
EXPECT_EGL_ERROR(EGL_BAD_DISPLAY); EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
} }
...@@ -35,18 +61,18 @@ TEST_P(EGLFeatureControlTest, InvalidDisplay) ...@@ -35,18 +61,18 @@ TEST_P(EGLFeatureControlTest, InvalidDisplay)
// Ensure eglQueryStringiANGLE generates EGL_BAD_PARAMETER if the index is negative. // Ensure eglQueryStringiANGLE generates EGL_BAD_PARAMETER if the index is negative.
TEST_P(EGLFeatureControlTest, NegativeIndex) TEST_P(EGLFeatureControlTest, NegativeIndex)
{ {
EXPECT_EQ(nullptr, ASSERT_TRUE(initTest());
eglQueryStringiANGLE(getEGLWindow()->getDisplay(), EGL_FEATURE_NAME_ANGLE, -1)); EXPECT_EQ(nullptr, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_NAME_ANGLE, -1));
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
} }
// Ensure eglQueryStringiANGLE generates EGL_BAD_PARAMETER if the index is out of bounds. // Ensure eglQueryStringiANGLE generates EGL_BAD_PARAMETER if the index is out of bounds.
TEST_P(EGLFeatureControlTest, IndexOutOfBounds) TEST_P(EGLFeatureControlTest, IndexOutOfBounds)
{ {
EGLDisplay dpy = getEGLWindow()->getDisplay(); ASSERT_TRUE(initTest());
egl::Display *display = static_cast<egl::Display *>(dpy); egl::Display *display = static_cast<egl::Display *>(mDisplay);
EXPECT_EQ(nullptr, EXPECT_EQ(nullptr, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_NAME_ANGLE,
eglQueryStringiANGLE(dpy, EGL_FEATURE_NAME_ANGLE, display->getFeatures().size())); display->getFeatures().size()));
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
} }
...@@ -54,7 +80,8 @@ TEST_P(EGLFeatureControlTest, IndexOutOfBounds) ...@@ -54,7 +80,8 @@ TEST_P(EGLFeatureControlTest, IndexOutOfBounds)
// options specified in EGL_ANGLE_feature_control. // options specified in EGL_ANGLE_feature_control.
TEST_P(EGLFeatureControlTest, InvalidName) TEST_P(EGLFeatureControlTest, InvalidName)
{ {
EXPECT_EQ(nullptr, eglQueryStringiANGLE(getEGLWindow()->getDisplay(), 100, 0)); ASSERT_TRUE(initTest());
EXPECT_EQ(nullptr, eglQueryStringiANGLE(mDisplay, 100, 0));
EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
} }
...@@ -63,19 +90,19 @@ TEST_P(EGLFeatureControlTest, InvalidName) ...@@ -63,19 +90,19 @@ TEST_P(EGLFeatureControlTest, InvalidName)
// FeatureList. // FeatureList.
TEST_P(EGLFeatureControlTest, QueryAll) TEST_P(EGLFeatureControlTest, QueryAll)
{ {
EGLDisplay dpy = getEGLWindow()->getDisplay(); ASSERT_TRUE(initTest());
egl::Display *display = static_cast<egl::Display *>(dpy); egl::Display *display = static_cast<egl::Display *>(mDisplay);
angle::FeatureList features = display->getFeatures(); angle::FeatureList features = display->getFeatures();
for (size_t i = 0; i < features.size(); i++) for (size_t i = 0; i < features.size(); i++)
{ {
EXPECT_STREQ(features[i]->name, eglQueryStringiANGLE(dpy, EGL_FEATURE_NAME_ANGLE, i)); EXPECT_STREQ(features[i]->name, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_NAME_ANGLE, i));
EXPECT_STREQ(FeatureCategoryToString(features[i]->category), EXPECT_STREQ(FeatureCategoryToString(features[i]->category),
eglQueryStringiANGLE(dpy, EGL_FEATURE_CATEGORY_ANGLE, i)); eglQueryStringiANGLE(mDisplay, EGL_FEATURE_CATEGORY_ANGLE, i));
EXPECT_STREQ(features[i]->description, EXPECT_STREQ(features[i]->description,
eglQueryStringiANGLE(dpy, EGL_FEATURE_DESCRIPTION_ANGLE, i)); eglQueryStringiANGLE(mDisplay, EGL_FEATURE_DESCRIPTION_ANGLE, i));
EXPECT_STREQ(features[i]->bug, eglQueryStringiANGLE(dpy, EGL_FEATURE_BUG_ANGLE, i)); EXPECT_STREQ(features[i]->bug, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_BUG_ANGLE, i));
EXPECT_STREQ(FeatureStatusToString(features[i]->enabled), EXPECT_STREQ(FeatureStatusToString(features[i]->enabled),
eglQueryStringiANGLE(dpy, EGL_FEATURE_STATUS_ANGLE, i)); eglQueryStringiANGLE(mDisplay, EGL_FEATURE_STATUS_ANGLE, i));
ASSERT_EGL_SUCCESS(); ASSERT_EGL_SUCCESS();
} }
} }
...@@ -84,19 +111,84 @@ TEST_P(EGLFeatureControlTest, QueryAll) ...@@ -84,19 +111,84 @@ TEST_P(EGLFeatureControlTest, QueryAll)
// attribute EGL_FEATURE_COUNT_ANGLE // attribute EGL_FEATURE_COUNT_ANGLE
TEST_P(EGLFeatureControlTest, FeatureCount) TEST_P(EGLFeatureControlTest, FeatureCount)
{ {
EGLDisplay dpy = getEGLWindow()->getDisplay(); ASSERT_TRUE(initTest());
egl::Display *display = static_cast<egl::Display *>(dpy); egl::Display *display = static_cast<egl::Display *>(mDisplay);
EGLAttrib value = -1; EGLAttrib value = -1;
EXPECT_EQ(static_cast<EGLBoolean>(EGL_TRUE), EXPECT_EQ(static_cast<EGLBoolean>(EGL_TRUE),
eglQueryDisplayAttribANGLE(dpy, EGL_FEATURE_COUNT_ANGLE, &value)); eglQueryDisplayAttribANGLE(mDisplay, EGL_FEATURE_COUNT_ANGLE, &value));
EXPECT_EQ(display->getFeatures().size(), static_cast<size_t>(value)); EXPECT_EQ(display->getFeatures().size(), static_cast<size_t>(value));
ASSERT_EGL_SUCCESS(); ASSERT_EGL_SUCCESS();
} }
// Submit a list of features to override when creating the display with eglGetPlatformDisplay, and
// ensure that the features are correctly overridden.
TEST_P(EGLFeatureControlTest, OverrideFeatures)
{
ASSERT_TRUE(initTest());
egl::Display *display = static_cast<egl::Display *>(mDisplay);
angle::FeatureList features = display->getFeatures();
// Build lists of features to enable/disabled. Toggle features we know are ok to toggle based
// from this list.
std::vector<const char *> enabled = std::vector<const char *>();
std::vector<const char *> disabled = std::vector<const char *>();
std::vector<bool> shouldBe = std::vector<bool>();
std::vector<std::string> testedFeatures = {
"add_and_true_to_loop_condition", // Safe to toggle GL
"clamp_frag_depth", // Safe to toggle GL
"clamp_point_size", // Safe to toggle GL and Vulkan
"flip_viewport_y", // Safe to toggle on Vulkan
"zero_max_lod", // Safe to toggle on D3D
"expand_integer_pow_expressions", // Safe to toggle on D3D
"rewrite_unary_minus_operator", // Safe to toggle on D3D
};
for (size_t i = 0; i < features.size(); i++)
{
bool toggle = std::find(testedFeatures.begin(), testedFeatures.end(),
std::string(features[i]->name)) != testedFeatures.end();
if (features[i]->enabled ^ toggle)
{
enabled.push_back(features[i]->name);
}
else
{
disabled.push_back(features[i]->name);
}
// Save what we expect the feature status will be when checking later.
shouldBe.push_back(features[i]->enabled ^ toggle);
}
disabled.push_back(0);
enabled.push_back(0);
// Terminate the old display (we just used it to collect features)
eglTerminate(mDisplay);
// Create a new display with these overridden features.
EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE,
GetParam().getRenderer(),
EGL_FEATURE_OVERRIDES_ENABLED_ANGLE,
reinterpret_cast<EGLAttrib>(enabled.data()),
EGL_FEATURE_OVERRIDES_DISABLED_ANGLE,
reinterpret_cast<EGLAttrib>(disabled.data()),
EGL_NONE};
EGLDisplay dpy_override = eglGetPlatformDisplay(
EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
ASSERT_EGL_SUCCESS();
ASSERT_TRUE(dpy_override != EGL_NO_DISPLAY);
ASSERT_TRUE(eglInitialize(dpy_override, nullptr, nullptr) == EGL_TRUE);
// Check that all features have the correct status (even the ones we toggled).
for (size_t i = 0; i < features.size(); i++)
{
EXPECT_STREQ(FeatureStatusToString(shouldBe[i]),
eglQueryStringiANGLE(dpy_override, EGL_FEATURE_STATUS_ANGLE, i));
}
}
ANGLE_INSTANTIATE_TEST(EGLFeatureControlTest, ANGLE_INSTANTIATE_TEST(EGLFeatureControlTest,
ES2_D3D9(), WithNoFixture(ES2_D3D9()),
ES2_D3D11(), WithNoFixture(ES2_D3D11()),
ES2_OPENGL(), WithNoFixture(ES2_OPENGL()),
ES2_VULKAN(), WithNoFixture(ES2_VULKAN()),
ES3_D3D11(), WithNoFixture(ES3_D3D11()),
ES3_OPENGL()); WithNoFixture(ES3_OPENGL()));
...@@ -301,7 +301,7 @@ class VulkanClearTest : public MaskedScissoredClearTestBase ...@@ -301,7 +301,7 @@ class VulkanClearTest : public MaskedScissoredClearTestBase
// depth/stencil format // depth/stencil format
void overrideFeaturesVk(FeaturesVk *featuresVk) override void overrideFeaturesVk(FeaturesVk *featuresVk) override
{ {
featuresVk->forceFeatureEnabled("force_fallback_format", true); featuresVk->overrideFeatures({"force_fallback_format"}, true);
} }
private: private:
......
...@@ -584,7 +584,7 @@ class TinyDepthStencilWorkaroundTest : public ANGLETest ...@@ -584,7 +584,7 @@ class TinyDepthStencilWorkaroundTest : public ANGLETest
// Override the workarounds to enable "tiny" depth/stencil textures. // Override the workarounds to enable "tiny" depth/stencil textures.
void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
{ {
workarounds->forceFeatureEnabled("emulate_tiny_stencil_textures", true); workarounds->overrideFeatures({"emulate_tiny_stencil_textures"}, true);
} }
}; };
......
...@@ -86,7 +86,7 @@ class DepthStencilTest : public ANGLETest ...@@ -86,7 +86,7 @@ class DepthStencilTest : public ANGLETest
// depth/stencil format // depth/stencil format
void overrideFeaturesVk(FeaturesVk *featuresVk) override void overrideFeaturesVk(FeaturesVk *featuresVk) override
{ {
featuresVk->forceFeatureEnabled("force_fallback_format", true); featuresVk->overrideFeatures({"force_fallback_format"}, true);
} }
void prepareSingleEmulatedWithPacked(); void prepareSingleEmulatedWithPacked();
......
...@@ -926,7 +926,7 @@ class AddDummyTextureNoRenderTargetTest : public ANGLETest ...@@ -926,7 +926,7 @@ class AddDummyTextureNoRenderTargetTest : public ANGLETest
void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
{ {
workarounds->forceFeatureEnabled("add_dummy_texture_no_render_target", true); workarounds->overrideFeatures({"add_dummy_texture_no_render_target"}, true);
} }
}; };
......
...@@ -287,8 +287,8 @@ class MultiviewRenderTest : public MultiviewFramebufferTestBase ...@@ -287,8 +287,8 @@ class MultiviewRenderTest : public MultiviewFramebufferTestBase
void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
{ {
workarounds->forceFeatureEnabled("select_view_in_geometry_shader", workarounds->overrideFeatures({"select_view_in_geometry_shader"},
GetParam().mForceUseGeometryShaderOnD3D); GetParam().mForceUseGeometryShaderOnD3D);
} }
virtual void testSetUp() {} virtual void testSetUp() {}
...@@ -529,8 +529,8 @@ class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase ...@@ -529,8 +529,8 @@ class MultiviewLayeredRenderTest : public MultiviewFramebufferTestBase
void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); } void TearDown() final { MultiviewFramebufferTestBase::FramebufferTestTearDown(); }
void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) final
{ {
workarounds->forceFeatureEnabled("select_view_in_geometry_shader", workarounds->overrideFeatures({"select_view_in_geometry_shader"},
GetParam().mForceUseGeometryShaderOnD3D); GetParam().mForceUseGeometryShaderOnD3D);
} }
}; };
......
...@@ -207,7 +207,7 @@ class VertexAttributeTest : public ANGLETest ...@@ -207,7 +207,7 @@ class VertexAttributeTest : public ANGLETest
// Override a feature to force emulation of attribute formats. // Override a feature to force emulation of attribute formats.
void overrideFeaturesVk(FeaturesVk *featuresVk) override void overrideFeaturesVk(FeaturesVk *featuresVk) override
{ {
featuresVk->forceFeatureEnabled("force_fallback_format", true); featuresVk->overrideFeatures({"force_fallback_format"}, true);
} }
GLuint compileMultiAttribProgram(GLint attribCount) GLuint compileMultiAttribProgram(GLint attribCount)
......
...@@ -171,8 +171,8 @@ class MultiviewBenchmark : public ANGLERenderTest, ...@@ -171,8 +171,8 @@ class MultiviewBenchmark : public ANGLERenderTest,
void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override void overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) override
{ {
workarounds->forceFeatureEnabled( workarounds->overrideFeatures(
"select_view_in_geometry_shader", {"select_view_in_geometry_shader"},
GetParam().multiviewOption == MultiviewOption::InstancedMultiviewGeometryShader); GetParam().multiviewOption == MultiviewOption::InstancedMultiviewGeometryShader);
} }
......
...@@ -265,8 +265,8 @@ MultiviewImplementationParams GeomShaderD3D11(GLint majorVersion, ...@@ -265,8 +265,8 @@ MultiviewImplementationParams GeomShaderD3D11(GLint majorVersion,
void MultiviewTest::overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) void MultiviewTest::overrideWorkaroundsD3D(WorkaroundsD3D *workarounds)
{ {
workarounds->forceFeatureEnabled("select_view_in_geometry_shader", workarounds->overrideFeatures({"select_view_in_geometry_shader"},
GetParam().mForceUseGeometryShaderOnD3D); GetParam().mForceUseGeometryShaderOnD3D);
} }
} // namespace angle } // namespace angle
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