Removed internal OpenGL contexts, reduced the number of temporary contexts that get created during runtime.
This commit is contained in:
parent
95828a85a2
commit
39208efb55
@ -29,10 +29,14 @@
|
|||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Window/Export.hpp>
|
#include <SFML/Window/Export.hpp>
|
||||||
|
#include <SFML/System/NonCopyable.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Context;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Base class for classes that require an OpenGL context
|
/// \brief Base class for classes that require an OpenGL context
|
||||||
///
|
///
|
||||||
@ -54,10 +58,27 @@ protected:
|
|||||||
~GlResource();
|
~GlResource();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Make sure that a valid OpenGL context exists in the current thread
|
/// \brief RAII helper class to temporarily lock an available context for use
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static void ensureGlContext();
|
class SFML_WINDOW_API TransientContextLock : NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TransientContextLock();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~TransientContextLock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Context* m_context; ///< Temporary context, in case we needed to create one
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -645,10 +645,6 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f
|
|||||||
// Delete the FT glyph
|
// Delete the FT glyph
|
||||||
FT_Done_Glyph(glyphDesc);
|
FT_Done_Glyph(glyphDesc);
|
||||||
|
|
||||||
// Force an OpenGL flush, so that the font's texture will appear updated
|
|
||||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
|
||||||
glCheck(glFlush());
|
|
||||||
|
|
||||||
// Done :)
|
// Done :)
|
||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,14 @@
|
|||||||
#include <SFML/Window/Context.hpp>
|
#include <SFML/Window/Context.hpp>
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
|
|
||||||
|
#if !defined(GL_MAJOR_VERSION)
|
||||||
|
#define GL_MAJOR_VERSION 0x821B
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(GL_MINOR_VERSION)
|
||||||
|
#define GL_MINOR_VERSION 0x821C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
@ -41,22 +49,41 @@ void ensureExtensionsInit()
|
|||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
{
|
{
|
||||||
const Context* context = Context::getActiveContext();
|
initialized = true;
|
||||||
|
|
||||||
if (!context)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sfogl_LoadFunctions();
|
sfogl_LoadFunctions();
|
||||||
|
|
||||||
ContextSettings settings = context->getSettings();
|
// Retrieve the context version number
|
||||||
|
int majorVersion = 0;
|
||||||
|
int minorVersion = 0;
|
||||||
|
|
||||||
if ((settings.majorVersion < 1) || ((settings.majorVersion == 1) && (settings.minorVersion < 1)))
|
// Try the new way first
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
|
||||||
|
|
||||||
|
if (glGetError() == GL_INVALID_ENUM)
|
||||||
|
{
|
||||||
|
// Try the old way
|
||||||
|
const GLubyte* version = glGetString(GL_VERSION);
|
||||||
|
if (version)
|
||||||
|
{
|
||||||
|
// The beginning of the returned string is "major.minor" (this is standard)
|
||||||
|
majorVersion = version[0] - '0';
|
||||||
|
minorVersion = version[2] - '0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can't get the version number, assume 1.1
|
||||||
|
majorVersion = 1;
|
||||||
|
minorVersion = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((majorVersion < 1) || ((majorVersion == 1) && (minorVersion < 1)))
|
||||||
{
|
{
|
||||||
err() << "sfml-graphics requires support for OpenGL 1.1 or greater" << std::endl;
|
err() << "sfml-graphics requires support for OpenGL 1.1 or greater" << std::endl;
|
||||||
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ m_depthBuffer(0)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
RenderTextureImplFBO::~RenderTextureImplFBO()
|
RenderTextureImplFBO::~RenderTextureImplFBO()
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
m_context->setActive(true);
|
||||||
|
|
||||||
// Destroy the depth buffer
|
// Destroy the depth buffer
|
||||||
if (m_depthBuffer)
|
if (m_depthBuffer)
|
||||||
@ -72,7 +72,7 @@ RenderTextureImplFBO::~RenderTextureImplFBO()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool RenderTextureImplFBO::isAvailable()
|
bool RenderTextureImplFBO::isAvailable()
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that extensions are initialized
|
// Make sure that extensions are initialized
|
||||||
priv::ensureExtensionsInit();
|
priv::ensureExtensionsInit();
|
||||||
|
@ -56,7 +56,8 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
sf::Mutex mutex;
|
sf::Mutex maxTextureUnitsMutex;
|
||||||
|
sf::Mutex isAvailableMutex;
|
||||||
|
|
||||||
GLint checkMaxTextureUnits()
|
GLint checkMaxTextureUnits()
|
||||||
{
|
{
|
||||||
@ -70,7 +71,7 @@ namespace
|
|||||||
GLint getMaxTextureUnits()
|
GLint getMaxTextureUnits()
|
||||||
{
|
{
|
||||||
// TODO: Remove this lock when it becomes unnecessary in C++11
|
// TODO: Remove this lock when it becomes unnecessary in C++11
|
||||||
sf::Lock lock(mutex);
|
sf::Lock lock(maxTextureUnitsMutex);
|
||||||
|
|
||||||
static GLint maxUnits = checkMaxTextureUnits();
|
static GLint maxUnits = checkMaxTextureUnits();
|
||||||
|
|
||||||
@ -116,53 +117,6 @@ namespace
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkShadersAvailable()
|
|
||||||
{
|
|
||||||
// Create a temporary context in case the user checks
|
|
||||||
// before a GlResource is created, thus initializing
|
|
||||||
// the shared context
|
|
||||||
if (!sf::Context::getActiveContext())
|
|
||||||
{
|
|
||||||
sf::Context context;
|
|
||||||
|
|
||||||
// Make sure that extensions are initialized
|
|
||||||
sf::priv::ensureExtensionsInit();
|
|
||||||
|
|
||||||
bool available = GLEXT_multitexture &&
|
|
||||||
GLEXT_shading_language_100 &&
|
|
||||||
GLEXT_shader_objects &&
|
|
||||||
GLEXT_vertex_shader &&
|
|
||||||
GLEXT_fragment_shader;
|
|
||||||
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that extensions are initialized
|
|
||||||
sf::priv::ensureExtensionsInit();
|
|
||||||
|
|
||||||
bool available = GLEXT_multitexture &&
|
|
||||||
GLEXT_shading_language_100 &&
|
|
||||||
GLEXT_shader_objects &&
|
|
||||||
GLEXT_vertex_shader &&
|
|
||||||
GLEXT_fragment_shader;
|
|
||||||
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
bool checkGeometryShadersAvailable()
|
|
||||||
{
|
|
||||||
// Create a temporary context in case the user checks
|
|
||||||
// before a GlResource is created, thus initializing
|
|
||||||
// the shared context
|
|
||||||
sf::Context context;
|
|
||||||
|
|
||||||
// Make sure that extensions are initialized
|
|
||||||
sf::priv::ensureExtensionsInit();
|
|
||||||
|
|
||||||
bool available = checkShadersAvailable() && GLEXT_geometry_shader4;
|
|
||||||
|
|
||||||
return available;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transforms an array of 2D vectors into a contiguous array of scalars
|
// Transforms an array of 2D vectors into a contiguous array of scalars
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::vector<T> flatten(const sf::Vector2<T>* vectorArray, std::size_t length)
|
std::vector<T> flatten(const sf::Vector2<T>* vectorArray, std::size_t length)
|
||||||
@ -236,8 +190,6 @@ struct Shader::UniformBinder : private NonCopyable
|
|||||||
{
|
{
|
||||||
if (currentProgram)
|
if (currentProgram)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
|
||||||
|
|
||||||
// Enable program object
|
// Enable program object
|
||||||
glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT));
|
glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT));
|
||||||
if (currentProgram != savedProgram)
|
if (currentProgram != savedProgram)
|
||||||
@ -259,6 +211,7 @@ struct Shader::UniformBinder : private NonCopyable
|
|||||||
glCheck(GLEXT_glUseProgramObject(savedProgram));
|
glCheck(GLEXT_glUseProgramObject(savedProgram));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TransientContextLock lock; ///< Lock to keep context active while uniform is bound
|
||||||
GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object
|
GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object
|
||||||
GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance
|
GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance
|
||||||
GLint location; ///< Uniform location, used by the surrounding sf::Shader code
|
GLint location; ///< Uniform location, used by the surrounding sf::Shader code
|
||||||
@ -278,7 +231,7 @@ m_uniforms ()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Shader::~Shader()
|
Shader::~Shader()
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Destroy effect program
|
// Destroy effect program
|
||||||
if (m_shaderProgram)
|
if (m_shaderProgram)
|
||||||
@ -592,7 +545,7 @@ void Shader::setUniform(const std::string& name, const Texture& texture)
|
|||||||
{
|
{
|
||||||
if (m_shaderProgram)
|
if (m_shaderProgram)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Find the location of the variable in the shader
|
// Find the location of the variable in the shader
|
||||||
int location = getUniformLocation(name);
|
int location = getUniformLocation(name);
|
||||||
@ -627,7 +580,7 @@ void Shader::setUniform(const std::string& name, CurrentTextureType)
|
|||||||
{
|
{
|
||||||
if (m_shaderProgram)
|
if (m_shaderProgram)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Find the location of the variable in the shader
|
// Find the location of the variable in the shader
|
||||||
m_currentTexture = getUniformLocation(name);
|
m_currentTexture = getUniformLocation(name);
|
||||||
@ -787,7 +740,7 @@ unsigned int Shader::getNativeHandle() const
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void Shader::bind(const Shader* shader)
|
void Shader::bind(const Shader* shader)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that we can use shaders
|
// Make sure that we can use shaders
|
||||||
if (!isAvailable())
|
if (!isAvailable())
|
||||||
@ -820,10 +773,26 @@ void Shader::bind(const Shader* shader)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Shader::isAvailable()
|
bool Shader::isAvailable()
|
||||||
{
|
{
|
||||||
// TODO: Remove this lock when it becomes unnecessary in C++11
|
Lock lock(isAvailableMutex);
|
||||||
Lock lock(mutex);
|
|
||||||
|
|
||||||
static bool available = checkShadersAvailable();
|
static bool checked = false;
|
||||||
|
static bool available = false;
|
||||||
|
|
||||||
|
if (!checked)
|
||||||
|
{
|
||||||
|
checked = true;
|
||||||
|
|
||||||
|
TransientContextLock contextLock;
|
||||||
|
|
||||||
|
// Make sure that extensions are initialized
|
||||||
|
sf::priv::ensureExtensionsInit();
|
||||||
|
|
||||||
|
available = GLEXT_multitexture &&
|
||||||
|
GLEXT_shading_language_100 &&
|
||||||
|
GLEXT_shader_objects &&
|
||||||
|
GLEXT_vertex_shader &&
|
||||||
|
GLEXT_fragment_shader;
|
||||||
|
}
|
||||||
|
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
@ -832,10 +801,22 @@ bool Shader::isAvailable()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Shader::isGeometryAvailable()
|
bool Shader::isGeometryAvailable()
|
||||||
{
|
{
|
||||||
// TODO: Remove this lock when it becomes unnecessary in C++11
|
Lock lock(isAvailableMutex);
|
||||||
Lock lock(mutex);
|
|
||||||
|
|
||||||
static bool available = checkGeometryShadersAvailable();
|
static bool checked = false;
|
||||||
|
static bool available = false;
|
||||||
|
|
||||||
|
if (!checked)
|
||||||
|
{
|
||||||
|
checked = true;
|
||||||
|
|
||||||
|
TransientContextLock contextLock;
|
||||||
|
|
||||||
|
// Make sure that extensions are initialized
|
||||||
|
sf::priv::ensureExtensionsInit();
|
||||||
|
|
||||||
|
available = isAvailable() && GLEXT_geometry_shader4;
|
||||||
|
}
|
||||||
|
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
@ -844,7 +825,7 @@ bool Shader::isGeometryAvailable()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode)
|
bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// First make sure that we can use shaders
|
// First make sure that we can use shaders
|
||||||
if (!isAvailable())
|
if (!isAvailable())
|
||||||
|
@ -40,39 +40,19 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
sf::Mutex mutex;
|
sf::Mutex idMutex;
|
||||||
|
sf::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)
|
||||||
sf::Uint64 getUniqueId()
|
sf::Uint64 getUniqueId()
|
||||||
{
|
{
|
||||||
sf::Lock lock(mutex);
|
sf::Lock lock(idMutex);
|
||||||
|
|
||||||
static sf::Uint64 id = 1; // start at 1, zero is "no texture"
|
static sf::Uint64 id = 1; // start at 1, zero is "no texture"
|
||||||
|
|
||||||
return id++;
|
return id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int checkMaximumTextureSize()
|
|
||||||
{
|
|
||||||
// Create a temporary context in case the user queries
|
|
||||||
// the size before a GlResource is created, thus
|
|
||||||
// initializing the shared context
|
|
||||||
if (!sf::Context::getActiveContext())
|
|
||||||
{
|
|
||||||
sf::Context context;
|
|
||||||
|
|
||||||
GLint size;
|
|
||||||
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
|
|
||||||
|
|
||||||
return static_cast<unsigned int>(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
GLint size;
|
|
||||||
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
|
|
||||||
|
|
||||||
return static_cast<unsigned int>(size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -118,7 +98,7 @@ Texture::~Texture()
|
|||||||
// Destroy the OpenGL texture
|
// Destroy the OpenGL texture
|
||||||
if (m_texture)
|
if (m_texture)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
GLuint texture = static_cast<GLuint>(m_texture);
|
GLuint texture = static_cast<GLuint>(m_texture);
|
||||||
glCheck(glDeleteTextures(1, &texture));
|
glCheck(glDeleteTextures(1, &texture));
|
||||||
@ -157,7 +137,7 @@ bool Texture::create(unsigned int width, unsigned int height)
|
|||||||
m_pixelsFlipped = false;
|
m_pixelsFlipped = false;
|
||||||
m_fboAttachment = false;
|
m_fboAttachment = false;
|
||||||
|
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Create the OpenGL texture if it doesn't exist yet
|
// Create the OpenGL texture if it doesn't exist yet
|
||||||
if (!m_texture)
|
if (!m_texture)
|
||||||
@ -265,10 +245,6 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area)
|
|||||||
{
|
{
|
||||||
update(image);
|
update(image);
|
||||||
|
|
||||||
// Force an OpenGL flush, so that the texture will appear updated
|
|
||||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
|
||||||
glCheck(glFlush());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -290,6 +266,8 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area)
|
|||||||
// Create the texture and upload the pixels
|
// Create the texture and upload the pixels
|
||||||
if (create(rectangle.width, rectangle.height))
|
if (create(rectangle.width, rectangle.height))
|
||||||
{
|
{
|
||||||
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that the current texture binding will be preserved
|
// Make sure that the current texture binding will be preserved
|
||||||
priv::TextureSaver save;
|
priv::TextureSaver save;
|
||||||
|
|
||||||
@ -333,7 +311,7 @@ Image Texture::copyToImage() const
|
|||||||
if (!m_texture)
|
if (!m_texture)
|
||||||
return Image();
|
return Image();
|
||||||
|
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that the current texture binding will be preserved
|
// Make sure that the current texture binding will be preserved
|
||||||
priv::TextureSaver save;
|
priv::TextureSaver save;
|
||||||
@ -424,7 +402,7 @@ void Texture::update(const Uint8* pixels, unsigned int width, unsigned int heigh
|
|||||||
|
|
||||||
if (pixels && m_texture)
|
if (pixels && m_texture)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that the current texture binding will be preserved
|
// Make sure that the current texture binding will be preserved
|
||||||
priv::TextureSaver save;
|
priv::TextureSaver save;
|
||||||
@ -436,6 +414,10 @@ void Texture::update(const Uint8* pixels, unsigned int width, unsigned int heigh
|
|||||||
m_hasMipmap = false;
|
m_hasMipmap = false;
|
||||||
m_pixelsFlipped = false;
|
m_pixelsFlipped = false;
|
||||||
m_cacheId = getUniqueId();
|
m_cacheId = getUniqueId();
|
||||||
|
|
||||||
|
// Force an OpenGL flush, so that the texture data will appear updated
|
||||||
|
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||||
|
glCheck(glFlush());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,6 +452,8 @@ void Texture::update(const Window& window, unsigned int x, unsigned int y)
|
|||||||
|
|
||||||
if (m_texture && window.setActive(true))
|
if (m_texture && window.setActive(true))
|
||||||
{
|
{
|
||||||
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that the current texture binding will be preserved
|
// Make sure that the current texture binding will be preserved
|
||||||
priv::TextureSaver save;
|
priv::TextureSaver save;
|
||||||
|
|
||||||
@ -480,6 +464,10 @@ void Texture::update(const Window& window, unsigned int x, unsigned int y)
|
|||||||
m_hasMipmap = false;
|
m_hasMipmap = false;
|
||||||
m_pixelsFlipped = true;
|
m_pixelsFlipped = true;
|
||||||
m_cacheId = getUniqueId();
|
m_cacheId = getUniqueId();
|
||||||
|
|
||||||
|
// Force an OpenGL flush, so that the texture will appear updated
|
||||||
|
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||||
|
glCheck(glFlush());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +481,7 @@ void Texture::setSmooth(bool smooth)
|
|||||||
|
|
||||||
if (m_texture)
|
if (m_texture)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that the current texture binding will be preserved
|
// Make sure that the current texture binding will be preserved
|
||||||
priv::TextureSaver save;
|
priv::TextureSaver save;
|
||||||
@ -544,7 +532,7 @@ void Texture::setRepeated(bool repeated)
|
|||||||
|
|
||||||
if (m_texture)
|
if (m_texture)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that the current texture binding will be preserved
|
// Make sure that the current texture binding will be preserved
|
||||||
priv::TextureSaver save;
|
priv::TextureSaver save;
|
||||||
@ -586,7 +574,7 @@ bool Texture::generateMipmap()
|
|||||||
if (!m_texture)
|
if (!m_texture)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that extensions are initialized
|
// Make sure that extensions are initialized
|
||||||
priv::ensureExtensionsInit();
|
priv::ensureExtensionsInit();
|
||||||
@ -613,7 +601,7 @@ void Texture::invalidateMipmap()
|
|||||||
if (!m_hasMipmap)
|
if (!m_hasMipmap)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that the current texture binding will be preserved
|
// Make sure that the current texture binding will be preserved
|
||||||
priv::TextureSaver save;
|
priv::TextureSaver save;
|
||||||
@ -628,7 +616,7 @@ void Texture::invalidateMipmap()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void Texture::bind(const Texture* texture, CoordinateType coordinateType)
|
void Texture::bind(const Texture* texture, CoordinateType coordinateType)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
if (texture && texture->m_texture)
|
if (texture && texture->m_texture)
|
||||||
{
|
{
|
||||||
@ -684,12 +672,21 @@ void Texture::bind(const Texture* texture, CoordinateType coordinateType)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
unsigned int Texture::getMaximumSize()
|
unsigned int Texture::getMaximumSize()
|
||||||
{
|
{
|
||||||
// TODO: Remove this lock when it becomes unnecessary in C++11
|
Lock lock(maximumSizeMutex);
|
||||||
Lock lock(mutex);
|
|
||||||
|
|
||||||
static unsigned int size = checkMaximumTextureSize();
|
static bool checked = false;
|
||||||
|
static GLint size = 0;
|
||||||
|
|
||||||
return size;
|
if (!checked)
|
||||||
|
{
|
||||||
|
checked = true;
|
||||||
|
|
||||||
|
TransientContextLock lock;
|
||||||
|
|
||||||
|
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<unsigned int>(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -722,7 +719,7 @@ unsigned int Texture::getNativeHandle() const
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
unsigned int Texture::getValidSize(unsigned int size)
|
unsigned int Texture::getValidSize(unsigned int size)
|
||||||
{
|
{
|
||||||
ensureGlContext();
|
TransientContextLock lock;
|
||||||
|
|
||||||
// Make sure that extensions are initialized
|
// Make sure that extensions are initialized
|
||||||
priv::ensureExtensionsInit();
|
priv::ensureExtensionsInit();
|
||||||
|
@ -28,24 +28,6 @@
|
|||||||
#include <SFML/Window/Context.hpp>
|
#include <SFML/Window/Context.hpp>
|
||||||
#include <SFML/Window/GlContext.hpp>
|
#include <SFML/Window/GlContext.hpp>
|
||||||
#include <SFML/System/ThreadLocalPtr.hpp>
|
#include <SFML/System/ThreadLocalPtr.hpp>
|
||||||
#include <SFML/OpenGL.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if defined(SFML_SYSTEM_WINDOWS)
|
|
||||||
|
|
||||||
typedef const GLubyte* (APIENTRY *glGetStringiFuncType)(GLenum, GLuint);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
typedef const GLubyte* (*glGetStringiFuncType)(GLenum, GLuint);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GL_NUM_EXTENSIONS)
|
|
||||||
#define GL_NUM_EXTENSIONS 0x821D
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@ -99,70 +81,16 @@ const Context* Context::getActiveContext()
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
GlFunctionPointer Context::getFunction(const char* name)
|
bool Context::isExtensionAvailable(const char* name)
|
||||||
{
|
{
|
||||||
return priv::GlContext::getFunction(name);
|
return priv::GlContext::isExtensionAvailable(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool Context::isExtensionAvailable(const char* name)
|
GlFunctionPointer Context::getFunction(const char* name)
|
||||||
{
|
{
|
||||||
static std::vector<std::string> extensions;
|
return priv::GlContext::getFunction(name);
|
||||||
static bool loaded = false;
|
|
||||||
|
|
||||||
if (!loaded)
|
|
||||||
{
|
|
||||||
const Context* context = getActiveContext();
|
|
||||||
|
|
||||||
if (!context)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const char* extensionString = NULL;
|
|
||||||
|
|
||||||
if(context->getSettings().majorVersion < 3)
|
|
||||||
{
|
|
||||||
// Try to load the < 3.0 way
|
|
||||||
extensionString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
const char* extension = extensionString;
|
|
||||||
|
|
||||||
while(*extensionString && (*extensionString != ' '))
|
|
||||||
extensionString++;
|
|
||||||
|
|
||||||
extensions.push_back(std::string(extension, extensionString));
|
|
||||||
}
|
|
||||||
while (*extensionString++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Try to load the >= 3.0 way
|
|
||||||
glGetStringiFuncType glGetStringiFunc = NULL;
|
|
||||||
glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(getFunction("glGetStringi"));
|
|
||||||
|
|
||||||
if (glGetStringiFunc)
|
|
||||||
{
|
|
||||||
int numExtensions = 0;
|
|
||||||
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
|
|
||||||
|
|
||||||
if (numExtensions)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
|
|
||||||
{
|
|
||||||
extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i));
|
|
||||||
|
|
||||||
extensions.push_back(extensionString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,9 +173,12 @@ EglContext::~EglContext()
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool EglContext::makeCurrent()
|
bool EglContext::makeCurrent(bool current)
|
||||||
{
|
{
|
||||||
|
if (current)
|
||||||
return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context));
|
return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, m_surface, m_surface, m_context));
|
||||||
|
|
||||||
|
return m_surface != EGL_NO_SURFACE && eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -209,6 +212,9 @@ void EglContext::createContext(EglContext* shared)
|
|||||||
else
|
else
|
||||||
toShared = EGL_NO_CONTEXT;
|
toShared = EGL_NO_CONTEXT;
|
||||||
|
|
||||||
|
if (toShared != EGL_NO_CONTEXT)
|
||||||
|
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||||
|
|
||||||
// Create EGL context
|
// Create EGL context
|
||||||
m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion));
|
m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion));
|
||||||
}
|
}
|
||||||
|
@ -83,10 +83,12 @@ public:
|
|||||||
/// \brief Activate the context as the current target
|
/// \brief Activate the context as the current target
|
||||||
/// for rendering
|
/// for rendering
|
||||||
///
|
///
|
||||||
|
/// \param current Whether to make the context current or no longer current
|
||||||
|
///
|
||||||
/// \return True on success, false if any error happened
|
/// \return True on success, false if any error happened
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual bool makeCurrent();
|
virtual bool makeCurrent(bool current);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Display what has been rendered to the context so far
|
/// \brief Display what has been rendered to the context so far
|
||||||
|
@ -31,9 +31,13 @@
|
|||||||
#include <SFML/System/Lock.hpp>
|
#include <SFML/System/Lock.hpp>
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
#include <SFML/OpenGL.hpp>
|
#include <SFML/OpenGL.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#if !defined(SFML_OPENGL_ES)
|
#if !defined(SFML_OPENGL_ES)
|
||||||
|
|
||||||
@ -126,6 +130,8 @@ namespace
|
|||||||
// AMD drivers have issues with internal synchronization
|
// AMD drivers have issues with internal synchronization
|
||||||
// We need to make sure that no operating system context
|
// We need to make sure that no operating system context
|
||||||
// or pixel format operations are performed simultaneously
|
// or pixel format operations are performed simultaneously
|
||||||
|
// This mutex is also used to protect the shared context
|
||||||
|
// from being locked on multiple threads
|
||||||
sf::Mutex mutex;
|
sf::Mutex mutex;
|
||||||
|
|
||||||
// This per-thread variable holds the current context for each thread
|
// This per-thread variable holds the current context for each thread
|
||||||
@ -134,35 +140,12 @@ namespace
|
|||||||
// The hidden, inactive context that will be shared with all other contexts
|
// The hidden, inactive context that will be shared with all other contexts
|
||||||
ContextType* sharedContext = NULL;
|
ContextType* sharedContext = NULL;
|
||||||
|
|
||||||
// Internal contexts
|
// This per-thread variable is set to point to the shared context
|
||||||
sf::ThreadLocalPtr<sf::Context> internalContext(NULL);
|
// if we had to acquire it when a TransientContextLock was required
|
||||||
std::set<sf::Context*> internalContexts;
|
sf::ThreadLocalPtr<sf::priv::GlContext> currentSharedContext(NULL);
|
||||||
sf::Mutex internalContextsMutex;
|
|
||||||
|
|
||||||
// Check if the internal context of the current thread is valid
|
// Supported OpenGL extensions
|
||||||
bool hasInternalContext()
|
std::vector<std::string> extensions;
|
||||||
{
|
|
||||||
// The internal context can be null...
|
|
||||||
if (!internalContext)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// ... or non-null but deleted from the list of internal contexts
|
|
||||||
sf::Lock lock(internalContextsMutex);
|
|
||||||
return internalContexts.find(internalContext) != internalContexts.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the internal context for the current thread
|
|
||||||
sf::Context* getInternalContext()
|
|
||||||
{
|
|
||||||
if (!hasInternalContext())
|
|
||||||
{
|
|
||||||
internalContext = new sf::Context;
|
|
||||||
sf::Lock lock(internalContextsMutex);
|
|
||||||
internalContexts.insert(internalContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
return internalContext;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -182,9 +165,53 @@ void GlContext::globalInit()
|
|||||||
sharedContext = new ContextType(NULL);
|
sharedContext = new ContextType(NULL);
|
||||||
sharedContext->initialize(ContextSettings());
|
sharedContext->initialize(ContextSettings());
|
||||||
|
|
||||||
// This call makes sure that:
|
// Load our extensions vector
|
||||||
// - the shared context is inactive (it must never be)
|
extensions.clear();
|
||||||
// - another valid context is activated in the current thread
|
|
||||||
|
// Check whether a >= 3.0 context is available
|
||||||
|
int majorVersion = 0;
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
|
||||||
|
|
||||||
|
if (glGetError() == GL_INVALID_ENUM)
|
||||||
|
{
|
||||||
|
// Try to load the < 3.0 way
|
||||||
|
const char* extensionString = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const char* extension = extensionString;
|
||||||
|
|
||||||
|
while(*extensionString && (*extensionString != ' '))
|
||||||
|
extensionString++;
|
||||||
|
|
||||||
|
extensions.push_back(std::string(extension, extensionString));
|
||||||
|
}
|
||||||
|
while (*extensionString++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Try to load the >= 3.0 way
|
||||||
|
glGetStringiFuncType glGetStringiFunc = NULL;
|
||||||
|
glGetStringiFunc = reinterpret_cast<glGetStringiFuncType>(getFunction("glGetStringi"));
|
||||||
|
|
||||||
|
if (glGetStringiFunc)
|
||||||
|
{
|
||||||
|
int numExtensions = 0;
|
||||||
|
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
|
||||||
|
|
||||||
|
if (numExtensions)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < static_cast<unsigned int>(numExtensions); ++i)
|
||||||
|
{
|
||||||
|
const char* extensionString = reinterpret_cast<const char*>(glGetStringiFunc(GL_EXTENSIONS, i));
|
||||||
|
|
||||||
|
extensions.push_back(extensionString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deactivate the shared context so that others can activate it when necessary
|
||||||
sharedContext->setActive(false);
|
sharedContext->setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,31 +227,59 @@ void GlContext::globalCleanup()
|
|||||||
// Destroy the shared context
|
// Destroy the shared context
|
||||||
delete sharedContext;
|
delete sharedContext;
|
||||||
sharedContext = NULL;
|
sharedContext = NULL;
|
||||||
|
|
||||||
// Destroy the internal contexts
|
|
||||||
Lock internalContextsLock(internalContextsMutex);
|
|
||||||
for (std::set<Context*>::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it)
|
|
||||||
delete *it;
|
|
||||||
internalContexts.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void GlContext::ensureContext()
|
void GlContext::acquireTransientContext()
|
||||||
{
|
{
|
||||||
// If there's no active context on the current thread, activate an internal one
|
// If a capable context is already active on this thread
|
||||||
if (!currentContext)
|
// there is no need to use the shared context for the operation
|
||||||
getInternalContext()->setActive(true);
|
if (currentContext)
|
||||||
|
{
|
||||||
|
currentSharedContext = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex.lock();
|
||||||
|
currentSharedContext = sharedContext;
|
||||||
|
sharedContext->setActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void GlContext::releaseTransientContext()
|
||||||
|
{
|
||||||
|
if (!currentSharedContext)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sharedContext->setActive(false);
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
GlContext* GlContext::create()
|
GlContext* GlContext::create()
|
||||||
{
|
{
|
||||||
|
// Make sure that there's an active context (context creation may need extensions, and thus a valid context)
|
||||||
|
assert(sharedContext != NULL);
|
||||||
|
|
||||||
Lock lock(mutex);
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
GlContext* context = NULL;
|
||||||
|
|
||||||
|
// We don't use acquireTransientContext here since we have
|
||||||
|
// to ensure we have exclusive access to the shared context
|
||||||
|
// in order to make sure it is not active during context creation
|
||||||
|
{
|
||||||
|
sharedContext->setActive(true);
|
||||||
|
|
||||||
// Create the context
|
// Create the context
|
||||||
GlContext* context = new ContextType(sharedContext);
|
context = new ContextType(sharedContext);
|
||||||
|
|
||||||
|
sharedContext->setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
context->initialize(ContextSettings());
|
context->initialize(ContextSettings());
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
@ -235,12 +290,24 @@ GlContext* GlContext::create()
|
|||||||
GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel)
|
GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel)
|
||||||
{
|
{
|
||||||
// Make sure that there's an active context (context creation may need extensions, and thus a valid context)
|
// Make sure that there's an active context (context creation may need extensions, and thus a valid context)
|
||||||
ensureContext();
|
assert(sharedContext != NULL);
|
||||||
|
|
||||||
Lock lock(mutex);
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
GlContext* context = NULL;
|
||||||
|
|
||||||
|
// We don't use acquireTransientContext here since we have
|
||||||
|
// to ensure we have exclusive access to the shared context
|
||||||
|
// in order to make sure it is not active during context creation
|
||||||
|
{
|
||||||
|
sharedContext->setActive(true);
|
||||||
|
|
||||||
// Create the context
|
// Create the context
|
||||||
GlContext* context = new ContextType(sharedContext, settings, owner, bitsPerPixel);
|
context = new ContextType(sharedContext, settings, owner, bitsPerPixel);
|
||||||
|
|
||||||
|
sharedContext->setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
context->initialize(settings);
|
context->initialize(settings);
|
||||||
context->checkSettings(settings);
|
context->checkSettings(settings);
|
||||||
|
|
||||||
@ -252,12 +319,24 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl*
|
|||||||
GlContext* GlContext::create(const ContextSettings& settings, unsigned int width, unsigned int height)
|
GlContext* GlContext::create(const ContextSettings& settings, unsigned int width, unsigned int height)
|
||||||
{
|
{
|
||||||
// Make sure that there's an active context (context creation may need extensions, and thus a valid context)
|
// Make sure that there's an active context (context creation may need extensions, and thus a valid context)
|
||||||
ensureContext();
|
assert(sharedContext != NULL);
|
||||||
|
|
||||||
Lock lock(mutex);
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
GlContext* context = NULL;
|
||||||
|
|
||||||
|
// We don't use acquireTransientContext here since we have
|
||||||
|
// to ensure we have exclusive access to the shared context
|
||||||
|
// in order to make sure it is not active during context creation
|
||||||
|
{
|
||||||
|
sharedContext->setActive(true);
|
||||||
|
|
||||||
// Create the context
|
// Create the context
|
||||||
GlContext* context = new ContextType(sharedContext, settings, width, height);
|
context = new ContextType(sharedContext, settings, width, height);
|
||||||
|
|
||||||
|
sharedContext->setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
context->initialize(settings);
|
context->initialize(settings);
|
||||||
context->checkSettings(settings);
|
context->checkSettings(settings);
|
||||||
|
|
||||||
@ -265,6 +344,13 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
bool GlContext::isExtensionAvailable(const char* name)
|
||||||
|
{
|
||||||
|
return std::find(extensions.begin(), extensions.end(), name) != extensions.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
GlFunctionPointer GlContext::getFunction(const char* name)
|
GlFunctionPointer GlContext::getFunction(const char* name)
|
||||||
{
|
{
|
||||||
@ -287,7 +373,10 @@ GlContext::~GlContext()
|
|||||||
{
|
{
|
||||||
// Deactivate the context before killing it, unless we're inside Cleanup()
|
// Deactivate the context before killing it, unless we're inside Cleanup()
|
||||||
if (sharedContext)
|
if (sharedContext)
|
||||||
setActive(false);
|
{
|
||||||
|
if (this == currentContext)
|
||||||
|
currentContext = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -308,7 +397,7 @@ bool GlContext::setActive(bool active)
|
|||||||
Lock lock(mutex);
|
Lock lock(mutex);
|
||||||
|
|
||||||
// Activate the context
|
// Activate the context
|
||||||
if (makeCurrent())
|
if (makeCurrent(true))
|
||||||
{
|
{
|
||||||
// Set it as the new current context for this thread
|
// Set it as the new current context for this thread
|
||||||
currentContext = this;
|
currentContext = this;
|
||||||
@ -329,9 +418,18 @@ bool GlContext::setActive(bool active)
|
|||||||
{
|
{
|
||||||
if (this == currentContext)
|
if (this == currentContext)
|
||||||
{
|
{
|
||||||
// To deactivate the context, we actually activate another one so that we make
|
Lock lock(mutex);
|
||||||
// sure that there is always an active context for subsequent graphics operations
|
|
||||||
return getInternalContext()->setActive(true);
|
// Deactivate the context
|
||||||
|
if (makeCurrent(false))
|
||||||
|
{
|
||||||
|
currentContext = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -73,10 +73,16 @@ public:
|
|||||||
static void globalCleanup();
|
static void globalCleanup();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Ensures that an OpenGL context is active in the current thread
|
/// \brief Acquires a context for short-term use on the current thread
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
static void ensureContext();
|
static void acquireTransientContext();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Releases a context after short-term use on the current thread
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static void releaseTransientContext();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Create a new context, not associated to a window
|
/// \brief Create a new context, not associated to a window
|
||||||
@ -120,6 +126,16 @@ public:
|
|||||||
static GlContext* create(const ContextSettings& settings, unsigned int width, unsigned int height);
|
static GlContext* create(const ContextSettings& settings, unsigned int width, unsigned int height);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Check whether a given OpenGL extension is available
|
||||||
|
///
|
||||||
|
/// \param name Name of the extension to check for
|
||||||
|
///
|
||||||
|
/// \return True if available, false if unavailable
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
static bool isExtensionAvailable(const char* name);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Get the address of an OpenGL function
|
/// \brief Get the address of an OpenGL function
|
||||||
///
|
///
|
||||||
@ -197,10 +213,12 @@ protected:
|
|||||||
/// \brief Activate the context as the current target
|
/// \brief Activate the context as the current target
|
||||||
/// for rendering
|
/// for rendering
|
||||||
///
|
///
|
||||||
|
/// \param current Whether to make the context current or no longer current
|
||||||
|
///
|
||||||
/// \return True on success, false if any error happened
|
/// \return True on success, false if any error happened
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual bool makeCurrent() = 0;
|
virtual bool makeCurrent(bool current) = 0;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Evaluate a pixel format configuration
|
/// \brief Evaluate a pixel format configuration
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Window/GlResource.hpp>
|
#include <SFML/Window/GlResource.hpp>
|
||||||
#include <SFML/Window/GlContext.hpp>
|
#include <SFML/Window/GlContext.hpp>
|
||||||
|
#include <SFML/Window/Context.hpp>
|
||||||
#include <SFML/System/Mutex.hpp>
|
#include <SFML/System/Mutex.hpp>
|
||||||
#include <SFML/System/Lock.hpp>
|
#include <SFML/System/Lock.hpp>
|
||||||
|
|
||||||
@ -43,7 +44,6 @@ namespace sf
|
|||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
GlResource::GlResource()
|
GlResource::GlResource()
|
||||||
{
|
|
||||||
{
|
{
|
||||||
// Protect from concurrent access
|
// Protect from concurrent access
|
||||||
Lock lock(mutex);
|
Lock lock(mutex);
|
||||||
@ -56,10 +56,6 @@ GlResource::GlResource()
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now make sure that there is an active OpenGL context in the current thread
|
|
||||||
priv::GlContext::ensureContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
GlResource::~GlResource()
|
GlResource::~GlResource()
|
||||||
@ -77,9 +73,31 @@ GlResource::~GlResource()
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void GlResource::ensureGlContext()
|
GlResource::TransientContextLock::TransientContextLock() :
|
||||||
|
m_context(0)
|
||||||
{
|
{
|
||||||
priv::GlContext::ensureContext();
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
m_context = new Context;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv::GlContext::acquireTransientContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
GlResource::TransientContextLock::~TransientContextLock()
|
||||||
|
{
|
||||||
|
if (m_context)
|
||||||
|
{
|
||||||
|
delete m_context;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv::GlContext::releaseTransientContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -137,10 +137,12 @@ protected:
|
|||||||
/// \brief Activate the context as the current target
|
/// \brief Activate the context as the current target
|
||||||
/// for rendering
|
/// for rendering
|
||||||
///
|
///
|
||||||
|
/// \param current Whether to make the context current or no longer current
|
||||||
|
///
|
||||||
/// \return True on success, false if any error happened
|
/// \return True on success, false if any error happened
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual bool makeCurrent();
|
virtual bool makeCurrent(bool current);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -104,6 +104,10 @@ m_window(0)
|
|||||||
SFContext::~SFContext()
|
SFContext::~SFContext()
|
||||||
{
|
{
|
||||||
[m_context clearDrawable];
|
[m_context clearDrawable];
|
||||||
|
|
||||||
|
if (m_context == [NSOpenGLContext currentContext])
|
||||||
|
[NSOpenGLContext clearCurrentContext];
|
||||||
|
|
||||||
[m_context release];
|
[m_context release];
|
||||||
|
|
||||||
[m_view release]; // Might be nil but we don't care.
|
[m_view release]; // Might be nil but we don't care.
|
||||||
@ -124,11 +128,19 @@ GlFunctionPointer SFContext::getFunction(const char* name)
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool SFContext::makeCurrent()
|
bool SFContext::makeCurrent(bool current)
|
||||||
|
{
|
||||||
|
if (current)
|
||||||
{
|
{
|
||||||
[m_context makeCurrentContext];
|
[m_context makeCurrentContext];
|
||||||
return m_context == [NSOpenGLContext currentContext]; // Should be true.
|
return m_context == [NSOpenGLContext currentContext]; // Should be true.
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[NSOpenGLContext clearCurrentContext];
|
||||||
|
return m_context != [NSOpenGLContext currentContext]; // Should be true.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -257,6 +269,17 @@ void SFContext::createContext(SFContext* shared,
|
|||||||
// Use the shared context if one is given.
|
// Use the shared context if one is given.
|
||||||
NSOpenGLContext* sharedContext = shared != NULL ? shared->m_context : nil;
|
NSOpenGLContext* sharedContext = shared != NULL ? shared->m_context : nil;
|
||||||
|
|
||||||
|
if (sharedContext != nil)
|
||||||
|
{
|
||||||
|
[NSOpenGLContext clearCurrentContext];
|
||||||
|
|
||||||
|
if (sharedContext == [NSOpenGLContext currentContext])
|
||||||
|
{
|
||||||
|
sf::err() << "Failed to deactivate shared context before sharing" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the context.
|
// Create the context.
|
||||||
m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt
|
m_context = [[NSOpenGLContext alloc] initWithFormat:pixFmt
|
||||||
shareContext:sharedContext];
|
shareContext:sharedContext];
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
// Headers
|
// Headers
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
|
#include <SFML/System/Mutex.hpp>
|
||||||
|
#include <SFML/System/Lock.hpp>
|
||||||
#include <SFML/Window/Unix/Display.hpp>
|
#include <SFML/Window/Unix/Display.hpp>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -38,6 +40,7 @@ namespace
|
|||||||
// The shared display and its reference counter
|
// The shared display and its reference counter
|
||||||
Display* sharedDisplay = NULL;
|
Display* sharedDisplay = NULL;
|
||||||
unsigned int referenceCount = 0;
|
unsigned int referenceCount = 0;
|
||||||
|
sf::Mutex mutex;
|
||||||
|
|
||||||
typedef std::map<std::string, Atom> AtomMap;
|
typedef std::map<std::string, Atom> AtomMap;
|
||||||
AtomMap atoms;
|
AtomMap atoms;
|
||||||
@ -50,6 +53,8 @@ namespace priv
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Display* OpenDisplay()
|
Display* OpenDisplay()
|
||||||
{
|
{
|
||||||
|
Lock lock(mutex);
|
||||||
|
|
||||||
if (referenceCount == 0)
|
if (referenceCount == 0)
|
||||||
{
|
{
|
||||||
sharedDisplay = XOpenDisplay(NULL);
|
sharedDisplay = XOpenDisplay(NULL);
|
||||||
@ -71,6 +76,8 @@ Display* OpenDisplay()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void CloseDisplay(Display* display)
|
void CloseDisplay(Display* display)
|
||||||
{
|
{
|
||||||
|
Lock lock(mutex);
|
||||||
|
|
||||||
assert(display == sharedDisplay);
|
assert(display == sharedDisplay);
|
||||||
|
|
||||||
referenceCount--;
|
referenceCount--;
|
||||||
|
@ -211,7 +211,7 @@ GlFunctionPointer GlxContext::getFunction(const char* name)
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool GlxContext::makeCurrent()
|
bool GlxContext::makeCurrent(bool current)
|
||||||
{
|
{
|
||||||
if (!m_context)
|
if (!m_context)
|
||||||
return false;
|
return false;
|
||||||
@ -222,6 +222,8 @@ bool GlxContext::makeCurrent()
|
|||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
|
if (current)
|
||||||
|
{
|
||||||
if (m_pbuffer)
|
if (m_pbuffer)
|
||||||
{
|
{
|
||||||
result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context);
|
result = glXMakeContextCurrent(m_display, m_pbuffer, m_pbuffer, m_context);
|
||||||
@ -230,6 +232,11 @@ bool GlxContext::makeCurrent()
|
|||||||
{
|
{
|
||||||
result = glXMakeCurrent(m_display, m_window, m_context);
|
result = glXMakeCurrent(m_display, m_window, m_context);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = glXMakeCurrent(m_display, None, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(GLX_DEBUGGING)
|
#if defined(GLX_DEBUGGING)
|
||||||
if (glxErrorOccurred)
|
if (glxErrorOccurred)
|
||||||
@ -686,6 +693,15 @@ void GlxContext::createContext(GlxContext* shared)
|
|||||||
// On an error, glXCreateContextAttribsARB will return 0 anyway
|
// On an error, glXCreateContextAttribsARB will return 0 anyway
|
||||||
GlxErrorHandler handler(m_display);
|
GlxErrorHandler handler(m_display);
|
||||||
|
|
||||||
|
if (toShare)
|
||||||
|
{
|
||||||
|
if (!glXMakeCurrent(m_display, None, NULL))
|
||||||
|
{
|
||||||
|
err() << "Failed to deactivate shared context before sharing" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the context
|
// Create the context
|
||||||
m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]);
|
m_context = glXCreateContextAttribsARB(m_display, *config, toShare, true, &attributes[0]);
|
||||||
|
|
||||||
@ -732,6 +748,15 @@ void GlxContext::createContext(GlxContext* shared)
|
|||||||
GlxErrorHandler handler(m_display);
|
GlxErrorHandler handler(m_display);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (toShare)
|
||||||
|
{
|
||||||
|
if (!glXMakeCurrent(m_display, None, NULL))
|
||||||
|
{
|
||||||
|
err() << "Failed to deactivate shared context before sharing" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the context, using the target window's visual
|
// Create the context, using the target window's visual
|
||||||
m_context = glXCreateContext(m_display, visualInfo, toShare, true);
|
m_context = glXCreateContext(m_display, visualInfo, toShare, true);
|
||||||
|
|
||||||
|
@ -94,10 +94,12 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Activate the context as the current target for rendering
|
/// \brief Activate the context as the current target for rendering
|
||||||
///
|
///
|
||||||
|
/// \param current Whether to make the context current or no longer current
|
||||||
|
///
|
||||||
/// \return True on success, false if any error happened
|
/// \return True on success, false if any error happened
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual bool makeCurrent();
|
virtual bool makeCurrent(bool current);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Display what has been rendered to the context so far
|
/// \brief Display what has been rendered to the context so far
|
||||||
|
@ -200,9 +200,9 @@ GlFunctionPointer WglContext::getFunction(const char* name)
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool WglContext::makeCurrent()
|
bool WglContext::makeCurrent(bool current)
|
||||||
{
|
{
|
||||||
return m_deviceContext && m_context && wglMakeCurrent(m_deviceContext, m_context);
|
return m_deviceContext && m_context && wglMakeCurrent(current ? m_deviceContext : NULL, current ? m_context : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -599,6 +599,18 @@ void WglContext::createContext(WglContext* shared)
|
|||||||
attributes.push_back(0);
|
attributes.push_back(0);
|
||||||
attributes.push_back(0);
|
attributes.push_back(0);
|
||||||
|
|
||||||
|
if (sharedContext)
|
||||||
|
{
|
||||||
|
static Mutex mutex;
|
||||||
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
if (!wglMakeCurrent(NULL, NULL))
|
||||||
|
{
|
||||||
|
err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the context
|
// Create the context
|
||||||
m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]);
|
m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]);
|
||||||
}
|
}
|
||||||
@ -657,6 +669,12 @@ void WglContext::createContext(WglContext* shared)
|
|||||||
static Mutex mutex;
|
static Mutex mutex;
|
||||||
Lock lock(mutex);
|
Lock lock(mutex);
|
||||||
|
|
||||||
|
if (!wglMakeCurrent(NULL, NULL))
|
||||||
|
{
|
||||||
|
err() << "Failed to deactivate shared context before sharing: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!wglShareLists(sharedContext, m_context))
|
if (!wglShareLists(sharedContext, m_context))
|
||||||
err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
|
err() << "Failed to share the OpenGL context: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,12 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Activate the context as the current target for rendering
|
/// \brief Activate the context as the current target for rendering
|
||||||
///
|
///
|
||||||
|
/// \param current Whether to make the context current or no longer current
|
||||||
|
///
|
||||||
/// \return True on success, false if any error happened
|
/// \return True on success, false if any error happened
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual bool makeCurrent();
|
virtual bool makeCurrent(bool current);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Display what has been rendered to the context so far
|
/// \brief Display what has been rendered to the context so far
|
||||||
|
@ -126,10 +126,12 @@ protected:
|
|||||||
/// \brief Activate the context as the current target
|
/// \brief Activate the context as the current target
|
||||||
/// for rendering
|
/// for rendering
|
||||||
///
|
///
|
||||||
|
/// \param current Whether to make the context current or no longer current
|
||||||
|
///
|
||||||
/// \return True on success, false if any error happened
|
/// \return True on success, false if any error happened
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual bool makeCurrent();
|
virtual bool makeCurrent(bool current);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -107,6 +107,9 @@ EaglContext::~EaglContext()
|
|||||||
|
|
||||||
// Restore the previous context
|
// Restore the previous context
|
||||||
[EAGLContext setCurrentContext:previousContext];
|
[EAGLContext setCurrentContext:previousContext];
|
||||||
|
|
||||||
|
if (m_context == [EAGLContext currentContext])
|
||||||
|
[EAGLContext setCurrentContext:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,9 +170,12 @@ void EaglContext::recreateRenderBuffers(SFView* glView)
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool EaglContext::makeCurrent()
|
bool EaglContext::makeCurrent(bool current)
|
||||||
{
|
{
|
||||||
|
if (current)
|
||||||
return [EAGLContext setCurrentContext:m_context];
|
return [EAGLContext setCurrentContext:m_context];
|
||||||
|
|
||||||
|
return [EAGLContext setCurrentContext:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -215,12 +221,18 @@ void EaglContext::createContext(EaglContext* shared,
|
|||||||
|
|
||||||
// Create the context
|
// Create the context
|
||||||
if (shared)
|
if (shared)
|
||||||
|
{
|
||||||
|
[EAGLContext setCurrentContext:nil];
|
||||||
|
|
||||||
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]];
|
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:[shared->m_context sharegroup]];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
|
m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
|
||||||
|
}
|
||||||
|
|
||||||
// Activate it
|
// Activate it
|
||||||
makeCurrent();
|
makeCurrent(true);
|
||||||
|
|
||||||
// Create the framebuffer (this is the only allowed drawable on iOS)
|
// Create the framebuffer (this is the only allowed drawable on iOS)
|
||||||
glGenFramebuffersOES(1, &m_framebuffer);
|
glGenFramebuffersOES(1, &m_framebuffer);
|
||||||
@ -230,6 +242,9 @@ void EaglContext::createContext(EaglContext* shared,
|
|||||||
|
|
||||||
// Attach the context to the GL view for future updates
|
// Attach the context to the GL view for future updates
|
||||||
window->getGlView().context = this;
|
window->getGlView().context = this;
|
||||||
|
|
||||||
|
// Deactivate it
|
||||||
|
makeCurrent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
Loading…
Reference in New Issue
Block a user