diff --git a/CMakeLists.txt b/CMakeLists.txt index f19c9b4..303d658 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,8 +70,8 @@ set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin") # compile flags -set(ARCH "-march=armv6k -mtune=mpcore -mfloat-abi=hard") -set(CPP3DS_ARM_FLAGS "-g -O2 ${ARCH} -fno-rtti -fno-exceptions -ffunction-sections -fdata-sections") +set(ARCH "-march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft") +set(CPP3DS_ARM_FLAGS "-g -O2 ${ARCH} -ffunction-sections -fdata-sections") set(CPP3DS_TEST_FLAGS "-g -O2") set(CPP3DS_EMU_FLAGS "-g -O2") diff --git a/src/emu3ds/Window/GlContext.cpp b/src/emu3ds/Window/GlContext.cpp new file mode 100644 index 0000000..e84631d --- /dev/null +++ b/src/emu3ds/Window/GlContext.cpp @@ -0,0 +1,337 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef cpp3ds::priv::GlContext ContextType; + +namespace +{ + // AMD drivers have issues with internal synchronization + // We need to make sure that no operating system context + // or pixel format operations are performed simultaneously + cpp3ds::Mutex mutex; + + // This per-thread variable holds the current context for each thread + cpp3ds::ThreadLocalPtr currentContext(NULL); + + // The hidden, inactive context that will be shared with all other contexts + ContextType* sharedContext = NULL; + + // Internal contexts + cpp3ds::ThreadLocalPtr internalContext(NULL); + std::set internalContexts; + cpp3ds::Mutex internalContextsMutex; + + // Check if the internal context of the current thread is valid + bool hasInternalContext() + { + // The internal context can be null... + if (!internalContext) + return false; + + // ... or non-null but deleted from the list of internal contexts + cpp3ds::Lock lock(internalContextsMutex); + return internalContexts.find(internalContext) != internalContexts.end(); + } + + // Retrieve the internal context for the current thread + cpp3ds::priv::GlContext* getInternalContext() + { + if (!hasInternalContext()) + { + internalContext = cpp3ds::priv::GlContext::create(); + cpp3ds::Lock lock(internalContextsMutex); + internalContexts.insert(internalContext); + } + + return internalContext; + } +} + + +namespace cpp3ds +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +void GlContext::globalInit() +{ + Lock lock(mutex); + + // Create the shared context + sharedContext = new ContextType(NULL); + sharedContext->initialize(); + + // This call makes sure that: + // - the shared context is inactive (it must never be) + // - another valid context is activated in the current thread + sharedContext->setActive(false); +} + + +//////////////////////////////////////////////////////////// +void GlContext::globalCleanup() +{ + Lock lock(mutex); + + // Destroy the shared context + delete sharedContext; + sharedContext = NULL; + + // Destroy the internal contexts + Lock internalContextsLock(internalContextsMutex); + for (std::set::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it) + delete *it; + internalContexts.clear(); +} + + +//////////////////////////////////////////////////////////// +void GlContext::ensureContext() +{ + // If there's no active context on the current thread, activate an internal one + if (!currentContext) + getInternalContext()->setActive(true); +} + + +//////////////////////////////////////////////////////////// +GlContext* GlContext::create() +{ + Lock lock(mutex); + + // Create the context + GlContext* context = new ContextType(sharedContext); + context->initialize(); + + return context; +} + + +//////////////////////////////////////////////////////////// +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) + ensureContext(); + + Lock lock(mutex); + + // Create the context + GlContext* context = new ContextType(sharedContext, settings, width, height); + context->initialize(); + context->checkSettings(settings); + + return context; +} + + +//////////////////////////////////////////////////////////// +GlContext::~GlContext() +{ + // Deactivate the context before killing it, unless we're inside Cleanup() + if (sharedContext) + setActive(false); + +#ifndef EMULATION + C3D_DestroyContext(m_context); +#endif +} + + +//////////////////////////////////////////////////////////// +bool GlContext::makeCurrent() +{ +#ifdef EMULATION + return true; +#else + return C3D_MakeCurrent(m_context); +#endif +} + + +//////////////////////////////////////////////////////////// +void GlContext::setVerticalSyncEnabled(bool enabled) +{ + // TODO: add vsync function to gl3ds +} + + +//////////////////////////////////////////////////////////// +void GlContext::display() { +#ifndef EMULATION + gl3ds_flushContext(m_context); +#endif +} + + +//////////////////////////////////////////////////////////// +const ContextSettings& GlContext::getSettings() const +{ + return m_settings; +} + + +//////////////////////////////////////////////////////////// +GLuint GlContext::getHandle() const +{ + return m_context; +} + + +//////////////////////////////////////////////////////////// +bool GlContext::setActive(bool active) +{ + if (active) + { + if (this != currentContext) + { + Lock lock(mutex); + + // Activate the context + if (makeCurrent()) + { + // Set it as the new current context for this thread + currentContext = this; + return true; + } + else + { + return false; + } + } + else + { + // This context is already the active one on this thread, don't do anything + return true; + } + } + else + { + if (this == currentContext) + { + // To deactivate the context, we actually activate another one so that we make + // sure that there is always an active context for subsequent graphics operations + return getInternalContext()->setActive(true); + } + else + { + // This context is not the active one on this thread, don't do anything + return true; + } + } +} + + +//////////////////////////////////////////////////////////// +GlContext::GlContext(GlContext* shared) +{ + m_settings = ContextSettings(); +#ifndef EMULATION + C3D_CreateContext(m_context, C3D_DEFAULT_CMDBUF_SIZE); +#endif +} + +GlContext::GlContext(GlContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) +{ + m_settings = settings; +#ifndef EMULATION + C3D_CreateContext(m_context, C3D_DEFAULT_CMDBUF_SIZE); +#endif +} + + +//////////////////////////////////////////////////////////// +int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated) +{ + int colorDiff = static_cast(bitsPerPixel) - colorBits; + int depthDiff = static_cast(settings.depthBits) - depthBits; + int stencilDiff = static_cast(settings.stencilBits) - stencilBits; + int antialiasingDiff = static_cast(settings.antialiasingLevel) - antialiasing; + + // Weight sub-scores so that better settings don't score equally as bad as worse settings + colorDiff *= ((colorDiff > 0) ? 100000 : 1); + depthDiff *= ((depthDiff > 0) ? 100000 : 1); + stencilDiff *= ((stencilDiff > 0) ? 100000 : 1); + antialiasingDiff *= ((antialiasingDiff > 0) ? 100000 : 1); + + // Aggregate the scores + int score = std::abs(colorDiff) + std::abs(depthDiff) + std::abs(stencilDiff) + std::abs(antialiasingDiff); + + // Make sure we prefer hardware acceleration over features + if (!accelerated) + score += 100000000; + + return score; +} + + +//////////////////////////////////////////////////////////// +void GlContext::initialize() +{ + // Activate the context + setActive(true); + + m_settings.attributeFlags = ContextSettings::Default; +/* + // Retrieve the context flags + int flags = 0; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + m_settings.attributeFlags |= ContextSettings::Debug; + + // Retrieve the context profile + int profile = 0; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile); + + if (profile & GL_CONTEXT_CORE_PROFILE_BIT) + m_settings.attributeFlags |= ContextSettings::Core; +*/ + // Enable antialiasing if needed +// if (m_settings.antialiasingLevel > 0) +// glEnable(GL_MULTISAMPLE); +} + + +//////////////////////////////////////////////////////////// +void GlContext::checkSettings(const ContextSettings& requestedSettings) +{ + // Perform checks to inform the user if they are getting a context they might not have expected +} + +} // namespace priv + +} // namespace cpp3ds