diff --git a/doc/changelog.dox b/doc/changelog.dox index dbfc4f199..4a614986c 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -60,6 +60,10 @@ See also: disabling @gl_extension{ANGLE,instanced_arrays} and @gl_extension{OES,texture_3D} extensions on SwiftShader due to missing suffixed entry points. See @ref opengl-workarounds for more information. +- New @cpp "swiftshader-broken-xfb-buffer-binding-target" @ce workaround + that's fixing misbehaving buffers when using + @ref GL::Buffer::TargetHint::TransformFeedback. See @ref opengl-workarounds + for more information. - New `--magnum-gpu-validation` @ref GL-Context-command-line "command-line option" and a corresponding environment variable to conveniently enable @gl_extension{KHR,debug} debug output diff --git a/src/Magnum/GL/Buffer.cpp b/src/Magnum/GL/Buffer.cpp index d5474a465..4f3b98b85 100644 --- a/src/Magnum/GL/Buffer.cpp +++ b/src/Magnum/GL/Buffer.cpp @@ -157,11 +157,17 @@ void Buffer::copy(Buffer& read, Buffer& write, const GLintptr readOffset, const } #endif -Buffer::Buffer(const TargetHint targetHint): _targetHint{targetHint}, _flags{ObjectFlag::DeleteOnDestruction} { - (this->*Context::current().state().buffer->createImplementation)(); +Buffer::Buffer(const TargetHint targetHint): _flags{ObjectFlag::DeleteOnDestruction} { + Implementation::BufferState& state = *Context::current().state().buffer; + (this->*state.createImplementation)(); + (this->*state.setTargetHintImplementation)(targetHint); CORRADE_INTERNAL_ASSERT(_id != Implementation::State::DisengagedBinding); } +Buffer::Buffer(GLuint id, TargetHint targetHint, ObjectFlags flags) noexcept: _id{id}, _flags{flags} { + (this->*Context::current().state().buffer->setTargetHintImplementation)(targetHint); +} + void Buffer::createImplementationDefault() { glGenBuffers(1, &_id); } @@ -186,6 +192,23 @@ Buffer::~Buffer() { glDeleteBuffers(1, &_id); } +Buffer& Buffer::setTargetHint(TargetHint hint) { + (this->*Context::current().state().buffer->setTargetHintImplementation)(hint); + return *this; +} + +void Buffer::setTargetHintImplementationDefault(const TargetHint hint) { + _targetHint = hint; +} + +#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) +void Buffer::setTargetHintImplementationSwiftShader(const TargetHint hint) { + /* See the "swiftshader-broken-xfb-buffer-binding-target" workaround for + details */ + _targetHint = hint == TargetHint::TransformFeedback ? TargetHint::Array : hint; +} +#endif + inline void Buffer::createIfNotAlready() { if(_flags & ObjectFlag::Created) return; diff --git a/src/Magnum/GL/Buffer.h b/src/Magnum/GL/Buffer.h index 11786486a..eeeaa9965 100644 --- a/src/Magnum/GL/Buffer.h +++ b/src/Magnum/GL/Buffer.h @@ -878,10 +878,7 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject { * to @fn_gl{BindBuffer}. Default target hint is @ref TargetHint::Array. * @see @ref setData(), @ref setSubData() */ - Buffer& setTargetHint(TargetHint hint) { - _targetHint = hint; - return *this; - } + Buffer& setTargetHint(TargetHint hint); #ifndef MAGNUM_TARGET_GLES2 /** @@ -1251,13 +1248,18 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject { #endif #endif - explicit Buffer(GLuint id, TargetHint targetHint, ObjectFlags flags) noexcept: _id{id}, _targetHint{targetHint}, _flags{flags} {} + explicit Buffer(GLuint id, TargetHint targetHint, ObjectFlags flags) noexcept; void MAGNUM_GL_LOCAL createImplementationDefault(); #ifndef MAGNUM_TARGET_GLES void MAGNUM_GL_LOCAL createImplementationDSA(); #endif + void MAGNUM_GL_LOCAL setTargetHintImplementationDefault(TargetHint hint); + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) + void MAGNUM_GL_LOCAL setTargetHintImplementationSwiftShader(TargetHint hint); + #endif + void MAGNUM_GL_LOCAL createIfNotAlready(); #ifndef MAGNUM_TARGET_WEBGL diff --git a/src/Magnum/GL/Implementation/BufferState.cpp b/src/Magnum/GL/Implementation/BufferState.cpp index e7956c878..6d280c83f 100644 --- a/src/Magnum/GL/Implementation/BufferState.cpp +++ b/src/Magnum/GL/Implementation/BufferState.cpp @@ -182,6 +182,17 @@ BufferState::BufferState(Context& context, std::vector& extensions) } #endif + #ifdef MAGNUM_TARGET_GLES + if((context.detectedDriver() & Context::DetectedDriver::SwiftShader) && + !context.isDriverWorkaroundDisabled("swiftshader-broken-xfb-buffer-binding-target")) + { + setTargetHintImplementation = &Buffer::setTargetHintImplementationSwiftShader; + } else + #endif + { + setTargetHintImplementation = &Buffer::setTargetHintImplementationDefault; + } + #ifdef MAGNUM_TARGET_GLES static_cast(context); static_cast(extensions); diff --git a/src/Magnum/GL/Implementation/BufferState.h b/src/Magnum/GL/Implementation/BufferState.h index a315cb241..81ebf01a4 100644 --- a/src/Magnum/GL/Implementation/BufferState.h +++ b/src/Magnum/GL/Implementation/BufferState.h @@ -54,6 +54,7 @@ struct BufferState { void(*copyImplementation)(Buffer&, Buffer&, GLintptr, GLintptr, GLsizeiptr); #endif void(Buffer::*createImplementation)(); + void(Buffer::*setTargetHintImplementation)(Buffer::TargetHint); void(Buffer::*getParameterImplementation)(GLenum, GLint*); #ifndef MAGNUM_TARGET_GLES2 void(Buffer::*getSubDataImplementation)(GLintptr, GLsizeiptr, GLvoid*); diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index 80aca8050..9e724d6e6 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -160,6 +160,16 @@ namespace { "swiftshader-no-es2-oes-texture-3d-entrypoints", #endif + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + /* SwiftShader 4.1.0 has special handling for binding buffers to the + transform feedback target, requiring an XFB object to be active when + a buffer is bound to GL_TRANSFORM_FEEDBACK_BUFFER and ignoring the + glBindBuffer() call otherwise. No other driver does that. As a + workaround, setting Buffer::TargetHint::TransformFeedback will make + it use Buffer::TargetHint::Array instead, as that works okay. */ + "swiftshader-broken-xfb-buffer-binding-target", + #endif + #ifndef MAGNUM_TARGET_GLES /* Even with the DSA variant, where GL_IMPLEMENTATION_COLOR_READ_* is passed to glGetNamedFramebufferParameter(), Mesa complains that the