Browse Source

GL: new apple-buffer-texture-detach-on-data-modify workaround.

mousecapture
Vladimír Vondruš 6 years ago
parent
commit
e97b04f66d
  1. 4
      doc/changelog.dox
  2. 89
      src/Magnum/GL/Buffer.cpp
  3. 48
      src/Magnum/GL/Buffer.h
  4. 15
      src/Magnum/GL/BufferTexture.cpp
  5. 8
      src/Magnum/GL/BufferTexture.h
  6. 13
      src/Magnum/GL/Implementation/BufferState.cpp
  7. 9
      src/Magnum/GL/Implementation/TextureState.cpp
  8. 15
      src/Magnum/GL/Implementation/driverSpecific.cpp
  9. 217
      src/Magnum/GL/Test/BufferTextureGLTest.cpp

4
doc/changelog.dox

@ -65,6 +65,10 @@ See also:
that attempted to fix this by doing an explicit buffer binding in some that attempted to fix this by doing an explicit buffer binding in some
cases. See @ref opengl-workarounds and [mosra/magnum#405](https://github.com/mosra/magnum/pull/405) cases. See @ref opengl-workarounds and [mosra/magnum#405](https://github.com/mosra/magnum/pull/405)
for more information. for more information.
- A @cpp "apple-buffer-texture-detach-on-data-modify" @ce workaround that
fixes crashes on Apple macOS when attempting to modify a @ref GL::Buffer
that's attached to a @ref GL::BufferTexture. See @ref opengl-workarounds
for more information.
@subsubsection changelog-latest-new-math Math library @subsubsection changelog-latest-new-math Math library

89
src/Magnum/GL/Buffer.cpp

@ -29,6 +29,9 @@
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Utility/Debug.h> #include <Corrade/Utility/Debug.h>
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
#include "Magnum/GL/BufferTexture.h"
#endif
#include "Magnum/GL/Context.h" #include "Magnum/GL/Context.h"
#include "Magnum/GL/Extensions.h" #include "Magnum/GL/Extensions.h"
#include "Magnum/GL/Implementation/State.h" #include "Magnum/GL/Implementation/State.h"
@ -546,6 +549,92 @@ bool Buffer::unmapImplementationDSA() {
#endif #endif
#endif #endif
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
/* If this buffer is attached to a buffer texture, we need to temporarily
detach it to avoid crashes in the macOS driver when doing buffer-modifying
operations. See the apple-buffer-texture-detach-on-setdata workaround for
more info. */
void Buffer::textureWorkaroundAppleBefore() {
/* No buffer texture attached or the texture no longer exists, nothing to
do */
if(!_bufferTexture || !glIsTexture(_bufferTexture)) {
_bufferTexture = 0; /* Avoid doing unnecessary work next time */
return;
}
/* Bind the buffer texture so we can ask for its state (as there's no
DSA on Apple to have a shortcut). The state tracking is a bit
complicated for textures, so playing it safe and using (friended)
private AbstractTexture APIs for that. */
BufferTexture t = BufferTexture::wrap(_bufferTexture);
t.bindInternal();
/* Check the current buffer binding for the texture. If it is no longer
our buffer, the buffer might get detached since or replaced with
another (which is fine, and much easier than maintaining the state
explicitly). */
GLuint currentBufferBinding;
glGetTexLevelParameteriv(GL_TEXTURE_BUFFER, 0, GL_TEXTURE_BUFFER_DATA_STORE_BINDING, reinterpret_cast<GLint*>(&currentBufferBinding));
if(currentBufferBinding != _id) {
_bufferTexture = 0; /* Avoid doing unnecessary work next time */
return;
}
/* In a saner bug workaround, i would just query
GL_TEXTURE_INTERNAL_FORMAT here. However, that's also broken,
returning GL_R8 always, so instead we have to cache it in the
Buffer instance. "Fortunately" macOS doesn't support
ARB_texture_range, so we don't need to store the offset + size,
just the format. */
CORRADE_INTERNAL_ASSERT(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_range>());
/* Temporarily detach the buffer. To avoid hitting more corner
cases, keep the same format as before. */
glTexBuffer(GL_TEXTURE_BUFFER, _bufferTextureFormat, 0);
}
void Buffer::textureWorkaroundAppleAfter() {
/* Put the buffer back, if we are supposed to be attached to a texture.
Assumes textureWorkaroundAppleBefore() was called and thus the texture
is bound. In case the state was stale, _bufferTexture was set to 0, so
this will get executed only when needed. */
if(_bufferTexture) glTexBuffer(GL_TEXTURE_BUFFER, _bufferTextureFormat, _id);
}
void Buffer::dataImplementationApple(const GLsizeiptr size, const GLvoid* const data, const BufferUsage usage) {
textureWorkaroundAppleBefore();
dataImplementationDefault(size, data, usage);
textureWorkaroundAppleAfter();
}
void Buffer::subDataImplementationApple(const GLintptr offset, const GLsizeiptr size, const GLvoid* const data) {
textureWorkaroundAppleBefore();
subDataImplementationDefault(offset, size, data);
textureWorkaroundAppleAfter();
}
void* Buffer::mapImplementationApple(const MapAccess access) {
textureWorkaroundAppleBefore();
void* const out = mapImplementationDefault(access);
textureWorkaroundAppleAfter();
return out;
}
void* Buffer::mapRangeImplementationApple(const GLintptr offset, const GLsizeiptr length, const MapFlags access) {
textureWorkaroundAppleBefore();
void* const out = mapRangeImplementationDefault(offset, length, access);
textureWorkaroundAppleAfter();
return out;
}
bool Buffer::unmapImplementationApple() {
textureWorkaroundAppleBefore();
const bool out = unmapImplementationDefault();
textureWorkaroundAppleAfter();
return out;
}
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
Debug& operator<<(Debug& debug, const Buffer::TargetHint value) { Debug& operator<<(Debug& debug, const Buffer::TargetHint value) {
debug << "GL::Buffer::TargetHint" << Debug::nospace; debug << "GL::Buffer::TargetHint" << Debug::nospace;

48
src/Magnum/GL/Buffer.h

@ -1214,43 +1214,69 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
void MAGNUM_GL_LOCAL getSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, GLvoid* data); void MAGNUM_GL_LOCAL getSubDataImplementationDSA(GLintptr offset, GLsizeiptr size, GLvoid* data);
#endif #endif
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void MAGNUM_GL_LOCAL textureWorkaroundAppleBefore();
void MAGNUM_GL_LOCAL textureWorkaroundAppleAfter();
#endif
void MAGNUM_GL_LOCAL dataImplementationDefault(GLsizeiptr size, const GLvoid* data, BufferUsage usage); void MAGNUM_GL_LOCAL dataImplementationDefault(GLsizeiptr size, const GLvoid* data, BufferUsage usage);
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void MAGNUM_GL_LOCAL dataImplementationApple(GLsizeiptr size, const GLvoid* data, BufferUsage usage);
#endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL dataImplementationDSA(GLsizeiptr size, const GLvoid* data, BufferUsage usage); void MAGNUM_GL_LOCAL dataImplementationDSA(GLsizeiptr size, const GLvoid* data, BufferUsage usage);
#endif #endif
void MAGNUM_GL_LOCAL subDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data); void MAGNUM_GL_LOCAL subDataImplementationDefault(GLintptr offset, GLsizeiptr size, const GLvoid* data);
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void MAGNUM_GL_LOCAL subDataImplementationApple(GLintptr offset, GLsizeiptr size, const GLvoid* data);
#endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL subDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data); void MAGNUM_GL_LOCAL subDataImplementationDSA(GLintptr offset, GLsizeiptr size, const GLvoid* data);
#endif #endif
void MAGNUM_GL_LOCAL invalidateImplementationNoOp(); void MAGNUM_GL_LOCAL invalidateImplementationNoOp();
/* No need for Apple-specific invalidateImplementation, as
GL_ARB_invalidate_subdata isn't supported */
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL invalidateImplementationARB(); void MAGNUM_GL_LOCAL invalidateImplementationARB();
#endif #endif
void MAGNUM_GL_LOCAL invalidateSubImplementationNoOp(GLintptr offset, GLsizeiptr length); void MAGNUM_GL_LOCAL invalidateSubImplementationNoOp(GLintptr offset, GLsizeiptr length);
/* No need for Apple-specific invalidateSubImplementation, as
GL_ARB_invalidate_subdata isn't supported */
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length); void MAGNUM_GL_LOCAL invalidateSubImplementationARB(GLintptr offset, GLsizeiptr length);
#endif #endif
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
void MAGNUM_GL_LOCAL * mapImplementationDefault(MapAccess access); void MAGNUM_GL_LOCAL * mapImplementationDefault(MapAccess access);
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void MAGNUM_GL_LOCAL * mapImplementationApple(MapAccess access);
#endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL * mapImplementationDSA(MapAccess access); void MAGNUM_GL_LOCAL * mapImplementationDSA(MapAccess access);
#endif #endif
void MAGNUM_GL_LOCAL * mapRangeImplementationDefault(GLintptr offset, GLsizeiptr length, MapFlags access); void MAGNUM_GL_LOCAL * mapRangeImplementationDefault(GLintptr offset, GLsizeiptr length, MapFlags access);
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void MAGNUM_GL_LOCAL * mapRangeImplementationApple(GLintptr offset, GLsizeiptr length, MapFlags access);
#endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL * mapRangeImplementationDSA(GLintptr offset, GLsizeiptr length, MapFlags access); void MAGNUM_GL_LOCAL * mapRangeImplementationDSA(GLintptr offset, GLsizeiptr length, MapFlags access);
#endif #endif
void MAGNUM_GL_LOCAL flushMappedRangeImplementationDefault(GLintptr offset, GLsizeiptr length); void MAGNUM_GL_LOCAL flushMappedRangeImplementationDefault(GLintptr offset, GLsizeiptr length);
/* No need for Apple-specific flushMappedRangeImplementation, as this
doesn't seem to hit the crashy code path */
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL flushMappedRangeImplementationDSA(GLintptr offset, GLsizeiptr length); void MAGNUM_GL_LOCAL flushMappedRangeImplementationDSA(GLintptr offset, GLsizeiptr length);
#endif #endif
bool MAGNUM_GL_LOCAL unmapImplementationDefault(); bool MAGNUM_GL_LOCAL unmapImplementationDefault();
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
bool MAGNUM_GL_LOCAL unmapImplementationApple();
#endif
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
bool MAGNUM_GL_LOCAL unmapImplementationDSA(); bool MAGNUM_GL_LOCAL unmapImplementationDSA();
#endif #endif
@ -1259,6 +1285,10 @@ class MAGNUM_GL_EXPORT Buffer: public AbstractObject {
GLuint _id; GLuint _id;
TargetHint _targetHint; TargetHint _targetHint;
ObjectFlags _flags; ObjectFlags _flags;
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
GLuint _bufferTexture{};
GLenum _bufferTextureFormat{};
#endif
}; };
#ifndef MAGNUM_TARGET_WEBGL #ifndef MAGNUM_TARGET_WEBGL
@ -1275,8 +1305,16 @@ MAGNUM_GL_EXPORT Debug& operator<<(Debug& debug, Buffer::Target value);
inline Buffer::Buffer(NoCreateT) noexcept: _id{0}, _targetHint{TargetHint::Array}, _flags{ObjectFlag::DeleteOnDestruction} {} inline Buffer::Buffer(NoCreateT) noexcept: _id{0}, _targetHint{TargetHint::Array}, _flags{ObjectFlag::DeleteOnDestruction} {}
inline Buffer::Buffer(Buffer&& other) noexcept: _id{other._id}, _targetHint{other._targetHint}, _flags{other._flags} { inline Buffer::Buffer(Buffer&& other) noexcept: _id{other._id}, _targetHint{other._targetHint}, _flags{other._flags}
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
, _bufferTexture{other._bufferTexture}, _bufferTextureFormat{other._bufferTextureFormat}
#endif
{
other._id = 0; other._id = 0;
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
other._bufferTexture = 0;
other._bufferTextureFormat = 0;
#endif
} }
inline Buffer& Buffer::operator=(Buffer&& other) noexcept { inline Buffer& Buffer::operator=(Buffer&& other) noexcept {
@ -1284,12 +1322,20 @@ inline Buffer& Buffer::operator=(Buffer&& other) noexcept {
swap(_id, other._id); swap(_id, other._id);
swap(_targetHint, other._targetHint); swap(_targetHint, other._targetHint);
swap(_flags, other._flags); swap(_flags, other._flags);
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
swap(_bufferTexture, other._bufferTexture);
swap(_bufferTextureFormat, other._bufferTextureFormat);
#endif
return *this; return *this;
} }
inline GLuint Buffer::release() { inline GLuint Buffer::release() {
const GLuint id = _id; const GLuint id = _id;
_id = 0; _id = 0;
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
_bufferTexture = 0;
_bufferTextureFormat = 0;
#endif
return id; return id;
} }

15
src/Magnum/GL/BufferTexture.cpp

@ -96,6 +96,21 @@ void BufferTexture::setBufferImplementationDefault(BufferTextureFormat internalF
glTexBuffer(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer ? buffer->id() : 0); glTexBuffer(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer ? buffer->id() : 0);
} }
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void BufferTexture::setBufferImplementationApple(BufferTextureFormat internalFormat, Buffer* buffer) {
/* Reference this texture from the buffer so next time setData() is called
we can temporarily detach it. See apple-buffer-texture-detach-on-setdata
for more information. */
if(buffer) {
buffer->_bufferTexture = id();
buffer->_bufferTextureFormat = GLenum(internalFormat);
}
bindInternal();
glTexBuffer(GL_TEXTURE_BUFFER, GLenum(internalFormat), buffer ? buffer->id() : 0);
}
#endif
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
void BufferTexture::setBufferImplementationEXT(BufferTextureFormat internalFormat, Buffer* buffer) { void BufferTexture::setBufferImplementationEXT(BufferTextureFormat internalFormat, Buffer* buffer) {
bindInternal(); bindInternal();

8
src/Magnum/GL/BufferTexture.h

@ -258,10 +258,16 @@ class MAGNUM_GL_EXPORT BufferTexture: public AbstractTexture {
private: private:
friend Implementation::TextureState; friend Implementation::TextureState;
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
friend Buffer;
#endif
explicit BufferTexture(GLuint id, ObjectFlags flags): AbstractTexture{id, GL_TEXTURE_BUFFER, flags} {} explicit BufferTexture(GLuint id, ObjectFlags flags): AbstractTexture{id, GL_TEXTURE_BUFFER, flags} {}
void MAGNUM_GL_LOCAL setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer); void MAGNUM_GL_LOCAL setBufferImplementationDefault(BufferTextureFormat internalFormat, Buffer* buffer);
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void MAGNUM_GL_LOCAL setBufferImplementationApple(BufferTextureFormat internalFormat, Buffer* buffer);
#endif
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL setBufferImplementationEXT(BufferTextureFormat internalFormat, Buffer* buffer); void MAGNUM_GL_LOCAL setBufferImplementationEXT(BufferTextureFormat internalFormat, Buffer* buffer);
#endif #endif
@ -270,6 +276,8 @@ class MAGNUM_GL_EXPORT BufferTexture: public AbstractTexture {
#endif #endif
void MAGNUM_GL_LOCAL setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size); void MAGNUM_GL_LOCAL setBufferRangeImplementationDefault(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size);
/* No need for Apple-specific setBufferRangeImplementation, as the
extension is not supported anyway */
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
void MAGNUM_GL_LOCAL setBufferRangeImplementationEXT(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size); void MAGNUM_GL_LOCAL setBufferRangeImplementationEXT(BufferTextureFormat internalFormat, Buffer& buffer, GLintptr offset, GLsizeiptr size);
#endif #endif

13
src/Magnum/GL/Implementation/BufferState.cpp

@ -177,6 +177,19 @@ BufferState::BufferState(Context& context, std::vector<std::string>& extensions)
setTargetHintImplementation = &Buffer::setTargetHintImplementationDefault; setTargetHintImplementation = &Buffer::setTargetHintImplementationDefault;
} }
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
if(!context.isDriverWorkaroundDisabled("apple-buffer-texture-detach-on-data-modify")) {
dataImplementation = &Buffer::dataImplementationApple;
subDataImplementation = &Buffer::subDataImplementationApple;
mapImplementation = &Buffer::mapImplementationApple;
mapRangeImplementation = &Buffer::mapRangeImplementationApple;
unmapImplementation = &Buffer::unmapImplementationApple;
/* No need for Apple-specific invalidate*Implementation, as the
extension isn't supported anyway */
CORRADE_INTERNAL_ASSERT(!context.isExtensionSupported<Extensions::ARB::invalidate_subdata>());
}
#endif
#ifdef MAGNUM_TARGET_GLES #ifdef MAGNUM_TARGET_GLES
static_cast<void>(context); static_cast<void>(context);
static_cast<void>(extensions); static_cast<void>(extensions);

9
src/Magnum/GL/Implementation/TextureState.cpp

@ -483,6 +483,15 @@ TextureState::TextureState(Context& context, std::vector<std::string>& extension
} }
#endif #endif
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
if(!context.isDriverWorkaroundDisabled("apple-buffer-texture-detach-on-data-modify")) {
setBufferImplementation = &BufferTexture::setBufferImplementationApple;
/* No need for Apple-specific setBufferRangeImplementation, as the
extension is not supported anyway */
CORRADE_INTERNAL_ASSERT(!context.isExtensionSupported<Extensions::ARB::texture_buffer_range>());
}
#endif
/* Allocate texture bindings array to hold all possible texture units */ /* Allocate texture bindings array to hold all possible texture units */
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
CORRADE_INTERNAL_ASSERT(maxTextureUnits > 0); CORRADE_INTERNAL_ASSERT(maxTextureUnits > 0);

15
src/Magnum/GL/Implementation/driverSpecific.cpp

@ -38,6 +38,21 @@ namespace {
/* Search the code for the following strings to see where they are implemented. */ /* Search the code for the following strings to see where they are implemented. */
std::vector<std::string> KnownWorkarounds{ std::vector<std::string> KnownWorkarounds{
/* [workarounds] */ /* [workarounds] */
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
/* Calling glBufferData(), glMapBuffer(), glMapBufferRange() or glUnmapBuffer()
on a buffer that's attached to a GL_TEXTURE_BUFFER crashes in
gleUpdateCtxDirtyStateForBufStampChange deep inside Apple's GLengine. A
workaround is to remember if a buffer is attached to a buffer texture,
temporarily detaching it, calling given data-modifying API and then
attaching it back with the same parameters. Unfortunately we need to cache
also the internal texture format, as GL_TEXTURE_INTERNAL_FORMAT query is
broken for buffer textures as well, returning always GL_R8 (the
spec-mandated default). "Fortunately" macOS doesn't support
ARB_texture_buffer_range so we don't need to store also offset/size, only
texture ID and its internal format, wasting 8 bytes per Buffer instance. */
"apple-buffer-texture-detach-on-data-modify",
#endif
#if defined(CORRADE_TARGET_ANDROID) && defined(MAGNUM_TARGET_GLES) #if defined(CORRADE_TARGET_ANDROID) && defined(MAGNUM_TARGET_GLES)
/* glBeginQuery() with GL_TIME_ELAPSED causes a GL_OUT_OF_MEMORY error when /* glBeginQuery() with GL_TIME_ELAPSED causes a GL_OUT_OF_MEMORY error when
running from the Android shell (through ADB). No such error happens in an running from the Android shell (through ADB). No such error happens in an

217
src/Magnum/GL/Test/BufferTextureGLTest.cpp

@ -23,6 +23,7 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <Corrade/Containers/Array.h>
#include <Corrade/TestSuite/Compare/Container.h> #include <Corrade/TestSuite/Compare/Container.h>
#include "Magnum/GL/Buffer.h" #include "Magnum/GL/Buffer.h"
@ -49,6 +50,16 @@ struct BufferTextureGLTest: OpenGLTester {
void setBufferOffset(); void setBufferOffset();
void resetBuffer(); void resetBuffer();
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void appleSetBufferSubData();
void appleSetBufferQueryData();
void appleSetBufferMap();
void appleSetBufferMapRange();
void appleSetBufferDataMoved();
void appleSetBufferDataBufferDetached();
void appleSetBufferDataTextureDeleted();
#endif
}; };
BufferTextureGLTest::BufferTextureGLTest() { BufferTextureGLTest::BufferTextureGLTest() {
@ -62,7 +73,18 @@ BufferTextureGLTest::BufferTextureGLTest() {
&BufferTextureGLTest::setBufferEmptyFirst, &BufferTextureGLTest::setBufferEmptyFirst,
&BufferTextureGLTest::setBufferOffset, &BufferTextureGLTest::setBufferOffset,
&BufferTextureGLTest::resetBuffer}); &BufferTextureGLTest::resetBuffer,
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
&BufferTextureGLTest::appleSetBufferSubData,
&BufferTextureGLTest::appleSetBufferQueryData,
&BufferTextureGLTest::appleSetBufferMap,
&BufferTextureGLTest::appleSetBufferMapRange,
&BufferTextureGLTest::appleSetBufferDataMoved,
&BufferTextureGLTest::appleSetBufferDataBufferDetached,
&BufferTextureGLTest::appleSetBufferDataTextureDeleted
#endif
});
} }
void BufferTextureGLTest::construct() { void BufferTextureGLTest::construct() {
@ -312,6 +334,199 @@ void BufferTextureGLTest::resetBuffer() {
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
} }
#if defined(CORRADE_TARGET_APPLE) && !defined(CORRADE_TARGET_IOS)
void BufferTextureGLTest::appleSetBufferSubData() {
if(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::ARB::texture_buffer_object::string() + std::string(" is not supported."));
BufferTexture texture;
Buffer buffer{Buffer::TargetHint::Texture};
buffer.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
texture.setBuffer(BufferTextureFormat::RG8UI, buffer);
MAGNUM_VERIFY_NO_GL_ERROR();
/* This also crashes unless worked around. Ugh. */
buffer.setSubData<UnsignedByte>(2, {0xf3, 0xab, 0x01, 0x57});
CORRADE_COMPARE(texture.size(), 8);
MAGNUM_VERIFY_NO_GL_ERROR();
}
void BufferTextureGLTest::appleSetBufferQueryData() {
if(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::ARB::texture_buffer_object::string() + std::string(" is not supported."));
BufferTexture texture;
Buffer buffer{Buffer::TargetHint::Texture};
buffer.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
texture.setBuffer(BufferTextureFormat::RG8UI, buffer);
MAGNUM_VERIFY_NO_GL_ERROR();
/* This shouldn't suffer from the same problem as setData() and so isn't
worked around in any way */
buffer.data();
CORRADE_COMPARE(texture.size(), 8);
MAGNUM_VERIFY_NO_GL_ERROR();
}
void BufferTextureGLTest::appleSetBufferMap() {
if(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::ARB::texture_buffer_object::string() + std::string(" is not supported."));
BufferTexture texture;
Buffer buffer{Buffer::TargetHint::Texture};
buffer.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
texture.setBuffer(BufferTextureFormat::RG8UI, buffer);
MAGNUM_VERIFY_NO_GL_ERROR();
/* This also crashes unless worked around. Ugh. */
const char* ptr = buffer.mapRead();
CORRADE_VERIFY(ptr);
/* This too */
buffer.unmap();
CORRADE_COMPARE(texture.size(), 8);
MAGNUM_VERIFY_NO_GL_ERROR();
}
void BufferTextureGLTest::appleSetBufferMapRange() {
if(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::ARB::texture_buffer_object::string() + std::string(" is not supported."));
BufferTexture texture;
Buffer buffer{Buffer::TargetHint::Texture};
buffer.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
texture.setBuffer(BufferTextureFormat::RG8UI, buffer);
MAGNUM_VERIFY_NO_GL_ERROR();
/* This also crashes unless worked around. Ugh. */
char* ptr = buffer.map(0, 16, Buffer::MapFlag::Write|Buffer::MapFlag::FlushExplicit);
CORRADE_VERIFY(ptr);
ptr[12] = 0x35;
/* This doesn't, it seems (yay!) */
buffer.flushMappedRange(8, 8);
/* This would crash again unless worked around */
buffer.unmap();
CORRADE_COMPARE(texture.size(), 8);
MAGNUM_VERIFY_NO_GL_ERROR();
}
void BufferTextureGLTest::appleSetBufferDataMoved() {
#ifndef MAGNUM_TARGET_GLES
if(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::ARB::texture_buffer_object::string() + std::string(" is not supported."));
#else
if(!Context::current().isExtensionSupported<Extensions::EXT::texture_buffer>())
CORRADE_SKIP(Extensions::EXT::texture_buffer::string() + std::string(" is not supported."));
#endif
BufferTexture texture;
Buffer a;
texture.setBuffer(BufferTextureFormat::RG8UI, a);
MAGNUM_VERIFY_NO_GL_ERROR();
if(Context::current().isVersionSupported(Version::GLES310))
CORRADE_COMPARE(texture.size(), 0);
/* Verify that the texture relation info survives moving the buffer */
a.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(texture.size(), 8);
Buffer b{std::move(a)};
b.setData<UnsignedByte>({0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(texture.size(), 4);
Buffer c;
c = std::move(b);
c.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(texture.size(), 8);
}
void BufferTextureGLTest::appleSetBufferDataBufferDetached() {
if(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::ARB::texture_buffer_object::string() + std::string(" is not supported."));
BufferTexture texture;
Buffer buffer;
buffer.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
texture.setBuffer(BufferTextureFormat::RG8UI, buffer);
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(texture.size(), 8);
texture.resetBuffer();
CORRADE_COMPARE(texture.size(), 0);
/* The buffer is no longer attached to the texture, so it should not
attempt to attach itself again */
buffer.setData<UnsignedByte>({0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f});
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(texture.size(), 0);
}
void BufferTextureGLTest::appleSetBufferDataTextureDeleted() {
if(!Context::current().isExtensionSupported<Extensions::ARB::texture_buffer_object>())
CORRADE_SKIP(Extensions::ARB::texture_buffer_object::string() + std::string(" is not supported."));
Buffer buffer;
buffer.setData<UnsignedByte>({
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
});
{
BufferTexture texture;
texture.setBuffer(BufferTextureFormat::RG8UI, buffer);
MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_COMPARE(texture.size(), 8);
}
/* The texture no longer exists, so the buffer should not attempt to
access it */
buffer.setData<UnsignedByte>({0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f});
MAGNUM_VERIFY_NO_GL_ERROR();
}
#endif
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::GL::Test::BufferTextureGLTest) CORRADE_TEST_MAIN(Magnum::GL::Test::BufferTextureGLTest)

Loading…
Cancel
Save