Make moving Shapes, swapping Textures and swapping VertexBuffers noexcept.

This commit is contained in:
binary1248 2023-03-05 14:03:27 +01:00 committed by Chris Thrasher
parent 66bec29aff
commit f4e0c4b4c0
13 changed files with 73 additions and 55 deletions

View File

@ -46,12 +46,6 @@ class Texture;
class SFML_GRAPHICS_API Shape : public Drawable, public Transformable class SFML_GRAPHICS_API Shape : public Drawable, public Transformable
{ {
public: public:
////////////////////////////////////////////////////////////
/// \brief Virtual destructor
///
////////////////////////////////////////////////////////////
~Shape() override;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Change the source texture of the shape /// \brief Change the source texture of the shape
/// ///

View File

@ -518,7 +518,7 @@ public:
/// \param right Instance to swap with /// \param right Instance to swap with
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void swap(Texture& right); void swap(Texture& right) noexcept;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the underlying OpenGL handle of the texture. /// \brief Get the underlying OpenGL handle of the texture.
@ -621,6 +621,15 @@ private:
std::uint64_t m_cacheId; //!< Unique number that identifies the texture to the render target's cache std::uint64_t m_cacheId; //!< Unique number that identifies the texture to the render target's cache
}; };
////////////////////////////////////////////////////////////
/// \brief Swap the contents of one texture with those of another
///
/// \param left First instance to swap
/// \param right Second instance to swap
///
////////////////////////////////////////////////////////////
void swap(Texture& left, Texture& right) noexcept;
} // namespace sf } // namespace sf

View File

@ -224,7 +224,7 @@ public:
/// \param right Instance to swap with /// \param right Instance to swap with
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void swap(VertexBuffer& right); void swap(VertexBuffer& right) noexcept;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get the underlying OpenGL handle of the vertex buffer. /// \brief Get the underlying OpenGL handle of the vertex buffer.
@ -338,6 +338,15 @@ private:
Usage m_usage{Stream}; //!< How this vertex buffer is to be used Usage m_usage{Stream}; //!< How this vertex buffer is to be used
}; };
////////////////////////////////////////////////////////////
/// \brief Swap the contents of one vertex buffer with those of another
///
/// \param left First instance to swap
/// \param right Second instance to swap
///
////////////////////////////////////////////////////////////
void swap(VertexBuffer& left, VertexBuffer& right) noexcept;
} // namespace sf } // namespace sf

View File

@ -126,6 +126,17 @@ endif()
sfml_find_package(Freetype INCLUDE "FREETYPE_INCLUDE_DIRS" LINK "FREETYPE_LIBRARY") sfml_find_package(Freetype INCLUDE "FREETYPE_INCLUDE_DIRS" LINK "FREETYPE_LIBRARY")
target_link_libraries(sfml-graphics PRIVATE Freetype) target_link_libraries(sfml-graphics PRIVATE Freetype)
# on some platforms (e.g. Raspberry Pi 3 armhf), GCC requires linking libatomic to use <atomic> features
# that aren't supported by native CPU instructions (64-bit atomic operations on 32-bit architecture)
if(SFML_COMPILER_GCC)
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("#include <atomic>
int main(){std::atomic_ullong x(1); return x.fetch_add(1);}" ATOMIC_TEST)
if(NOT ATOMIC_TEST)
target_link_libraries(sfml-graphics PRIVATE atomic)
endif()
endif()
# add preprocessor symbols # add preprocessor symbols
target_compile_definitions(sfml-graphics PRIVATE "STBI_FAILURE_USERMSG") target_compile_definitions(sfml-graphics PRIVATE "STBI_FAILURE_USERMSG")

View File

@ -48,10 +48,6 @@ sf::Vector2f computeNormal(const sf::Vector2f& p1, const sf::Vector2f& p2)
namespace sf namespace sf
{ {
////////////////////////////////////////////////////////////
Shape::~Shape() = default;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Shape::setTexture(const Texture* texture, bool resetRect) void Shape::setTexture(const Texture* texture, bool resetRect)
{ {

View File

@ -33,10 +33,10 @@
#include <SFML/Window/Context.hpp> #include <SFML/Window/Context.hpp>
#include <SFML/Window/Window.hpp> #include <SFML/Window/Window.hpp>
#include <atomic>
#include <cassert> #include <cassert>
#include <climits> #include <climits>
#include <cstring> #include <cstring>
#include <mutex>
#include <ostream> #include <ostream>
@ -45,18 +45,13 @@ namespace
// A nested named namespace is used here to allow unity builds of SFML. // A nested named namespace is used here to allow unity builds of SFML.
namespace TextureImpl namespace TextureImpl
{ {
std::recursive_mutex idMutex;
std::recursive_mutex maximumSizeMutex;
// Thread-safe unique identifier generator, // Thread-safe unique identifier generator,
// is used for states cache (see RenderTarget) // is used for states cache (see RenderTarget)
std::uint64_t getUniqueId() std::uint64_t getUniqueId() noexcept
{ {
std::lock_guard lock(idMutex); static std::atomic<std::uint64_t> id(1); // start at 1, zero is "no texture"
static std::uint64_t id = 1; // start at 1, zero is "no texture" return id.fetch_add(1);
return id++;
} }
} // namespace TextureImpl } // namespace TextureImpl
} // namespace } // namespace
@ -832,21 +827,18 @@ void Texture::bind(const Texture* texture, CoordinateType coordinateType)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
unsigned int Texture::getMaximumSize() unsigned int Texture::getMaximumSize()
{ {
std::lock_guard lock(TextureImpl::maximumSizeMutex); static const unsigned int size = []()
static bool checked = false;
static GLint size = 0;
if (!checked)
{ {
checked = true;
TransientContextLock transientLock; TransientContextLock transientLock;
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size)); GLint value = 0;
}
return static_cast<unsigned int>(size); glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value));
return static_cast<unsigned int>(value);
}();
return size;
} }
@ -862,7 +854,7 @@ Texture& Texture::operator=(const Texture& right)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Texture::swap(Texture& right) void Texture::swap(Texture& right) noexcept
{ {
std::swap(m_size, right.m_size); std::swap(m_size, right.m_size);
std::swap(m_actualSize, right.m_actualSize); std::swap(m_actualSize, right.m_actualSize);
@ -905,4 +897,11 @@ unsigned int Texture::getValidSize(unsigned int size)
} }
} }
////////////////////////////////////////////////////////////
void swap(Texture& left, Texture& right) noexcept
{
left.swap(right);
}
} // namespace sf } // namespace sf

View File

@ -33,7 +33,6 @@
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
#include <mutex>
#include <ostream> #include <ostream>
#include <utility> #include <utility>
@ -42,8 +41,6 @@ namespace
// A nested named namespace is used here to allow unity builds of SFML. // A nested named namespace is used here to allow unity builds of SFML.
namespace VertexBufferImpl namespace VertexBufferImpl
{ {
std::recursive_mutex isAvailableMutex;
GLenum usageToGlEnum(sf::VertexBuffer::Usage usage) GLenum usageToGlEnum(sf::VertexBuffer::Usage usage)
{ {
switch (usage) switch (usage)
@ -274,7 +271,7 @@ VertexBuffer& VertexBuffer::operator=(const VertexBuffer& right)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void VertexBuffer::swap(VertexBuffer& right) void VertexBuffer::swap(VertexBuffer& right) noexcept
{ {
std::swap(m_size, right.m_size); std::swap(m_size, right.m_size);
std::swap(m_buffer, right.m_buffer); std::swap(m_buffer, right.m_buffer);
@ -333,22 +330,15 @@ VertexBuffer::Usage VertexBuffer::getUsage() const
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool VertexBuffer::isAvailable() bool VertexBuffer::isAvailable()
{ {
std::lock_guard lock(VertexBufferImpl::isAvailableMutex); static const bool available = []() -> bool
static bool checked = false;
static bool available = false;
if (!checked)
{ {
checked = true;
TransientContextLock contextLock; TransientContextLock contextLock;
// Make sure that extensions are initialized // Make sure that extensions are initialized
sf::priv::ensureExtensionsInit(); sf::priv::ensureExtensionsInit();
available = GLEXT_vertex_buffer_object; return GLEXT_vertex_buffer_object;
} }();
return available; return available;
} }
@ -361,4 +351,11 @@ void VertexBuffer::draw(RenderTarget& target, const RenderStates& states) const
target.draw(*this, 0, m_size, states); target.draw(*this, 0, m_size, states);
} }
////////////////////////////////////////////////////////////
void swap(VertexBuffer& left, VertexBuffer& right) noexcept
{
left.swap(right);
}
} // namespace sf } // namespace sf

View File

@ -7,8 +7,8 @@
static_assert(std::is_copy_constructible_v<sf::CircleShape>); static_assert(std::is_copy_constructible_v<sf::CircleShape>);
static_assert(std::is_copy_assignable_v<sf::CircleShape>); static_assert(std::is_copy_assignable_v<sf::CircleShape>);
static_assert(std::is_move_constructible_v<sf::CircleShape>); static_assert(std::is_nothrow_move_constructible_v<sf::CircleShape>);
static_assert(std::is_move_assignable_v<sf::CircleShape>); static_assert(std::is_nothrow_move_assignable_v<sf::CircleShape>);
TEST_CASE("[Graphics] sf::CircleShape") TEST_CASE("[Graphics] sf::CircleShape")
{ {

View File

@ -7,8 +7,8 @@
static_assert(std::is_copy_constructible_v<sf::ConvexShape>); static_assert(std::is_copy_constructible_v<sf::ConvexShape>);
static_assert(std::is_copy_assignable_v<sf::ConvexShape>); static_assert(std::is_copy_assignable_v<sf::ConvexShape>);
static_assert(std::is_move_constructible_v<sf::ConvexShape>); static_assert(std::is_nothrow_move_constructible_v<sf::ConvexShape>);
static_assert(std::is_move_assignable_v<sf::ConvexShape>); static_assert(std::is_nothrow_move_assignable_v<sf::ConvexShape>);
TEST_CASE("[Graphics] sf::ConvexShape") TEST_CASE("[Graphics] sf::ConvexShape")
{ {

View File

@ -7,8 +7,8 @@
static_assert(std::is_copy_constructible_v<sf::RectangleShape>); static_assert(std::is_copy_constructible_v<sf::RectangleShape>);
static_assert(std::is_copy_assignable_v<sf::RectangleShape>); static_assert(std::is_copy_assignable_v<sf::RectangleShape>);
static_assert(std::is_move_constructible_v<sf::RectangleShape>); static_assert(std::is_nothrow_move_constructible_v<sf::RectangleShape>);
static_assert(std::is_move_assignable_v<sf::RectangleShape>); static_assert(std::is_nothrow_move_assignable_v<sf::RectangleShape>);
TEST_CASE("[Graphics] sf::RectangleShape") TEST_CASE("[Graphics] sf::RectangleShape")
{ {

View File

@ -9,7 +9,8 @@ static_assert(!std::is_constructible_v<sf::Shape>);
static_assert(!std::is_copy_constructible_v<sf::Shape>); static_assert(!std::is_copy_constructible_v<sf::Shape>);
static_assert(std::is_copy_assignable_v<sf::Shape>); static_assert(std::is_copy_assignable_v<sf::Shape>);
static_assert(!std::is_move_constructible_v<sf::Shape>); static_assert(!std::is_move_constructible_v<sf::Shape>);
static_assert(std::is_move_assignable_v<sf::Shape>); static_assert(std::is_nothrow_move_assignable_v<sf::Shape>);
static_assert(std::has_virtual_destructor_v<sf::Shape>);
class TriangleShape : public sf::Shape class TriangleShape : public sf::Shape
{ {

View File

@ -11,6 +11,7 @@ static_assert(std::is_move_constructible_v<sf::Texture>);
static_assert(!std::is_nothrow_move_constructible_v<sf::Texture>); static_assert(!std::is_nothrow_move_constructible_v<sf::Texture>);
static_assert(std::is_move_assignable_v<sf::Texture>); static_assert(std::is_move_assignable_v<sf::Texture>);
static_assert(!std::is_nothrow_move_assignable_v<sf::Texture>); static_assert(!std::is_nothrow_move_assignable_v<sf::Texture>);
static_assert(std::is_nothrow_swappable_v<sf::Texture>);
TEST_CASE("[Graphics] sf::Texture" * doctest::skip(skipDisplayTests)) TEST_CASE("[Graphics] sf::Texture" * doctest::skip(skipDisplayTests))
{ {

View File

@ -15,6 +15,7 @@ static_assert(std::is_move_constructible_v<sf::VertexBuffer>);
static_assert(!std::is_nothrow_move_constructible_v<sf::VertexBuffer>); static_assert(!std::is_nothrow_move_constructible_v<sf::VertexBuffer>);
static_assert(std::is_move_assignable_v<sf::VertexBuffer>); static_assert(std::is_move_assignable_v<sf::VertexBuffer>);
static_assert(!std::is_nothrow_move_assignable_v<sf::VertexBuffer>); static_assert(!std::is_nothrow_move_assignable_v<sf::VertexBuffer>);
static_assert(std::is_nothrow_swappable_v<sf::VertexBuffer>);
// Skip these tests because they produce flakey failures in CI when using xvfb-run // Skip these tests because they produce flakey failures in CI when using xvfb-run
TEST_CASE("[Graphics] sf::VertexBuffer" * doctest::skip(true)) TEST_CASE("[Graphics] sf::VertexBuffer" * doctest::skip(true))
@ -148,7 +149,7 @@ TEST_CASE("[Graphics] sf::VertexBuffer" * doctest::skip(true))
sf::VertexBuffer vertexBuffer2(sf::PrimitiveType::TriangleStrip, sf::VertexBuffer::Stream); sf::VertexBuffer vertexBuffer2(sf::PrimitiveType::TriangleStrip, sf::VertexBuffer::Stream);
CHECK(vertexBuffer2.create(60)); CHECK(vertexBuffer2.create(60));
vertexBuffer1.swap(vertexBuffer2); std::swap(vertexBuffer1, vertexBuffer2);
CHECK(vertexBuffer1.getVertexCount() == 60); CHECK(vertexBuffer1.getVertexCount() == 60);
CHECK(vertexBuffer1.getNativeHandle() != 0); CHECK(vertexBuffer1.getNativeHandle() != 0);