blob: 33535376c66d4120855f044a2fe1cfd65641c12b [file] [log] [blame]
/*
* Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "SurfaceOpenVG.h"
#include "IntSize.h"
#include "PainterOpenVG.h"
#if PLATFORM(EGL)
#include "EGLDisplayOpenVG.h"
#include "EGLUtils.h"
#endif
#include <wtf/Assertions.h>
namespace WebCore {
PainterOpenVG* SurfaceOpenVG::s_currentPainter = 0;
SurfaceOpenVG* SurfaceOpenVG::currentSurface()
{
#if PLATFORM(EGL)
return EGLDisplayOpenVG::currentSurface();
#else
ASSERT_NOT_REACHED();
return 0;
#endif
}
#if PLATFORM(EGL)
SurfaceOpenVG::SurfaceOpenVG(const IntSize& size, const EGLDisplay& display, EGLConfig* confPtr, EGLint* errorCode)
: m_activePainter(0)
, m_eglDisplay(display)
, m_eglSurface(EGL_NO_SURFACE)
, m_eglContext(EGL_NO_CONTEXT)
{
ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultPbufferConfig();
m_eglSurface = displayManager->createPbufferSurface(size, config, errorCode);
if (m_eglSurface == EGL_NO_SURFACE)
return;
m_eglContext = displayManager->contextForSurface(m_eglSurface);
EGLDisplayOpenVG::registerPlatformSurface(this);
}
SurfaceOpenVG::SurfaceOpenVG(EGLClientBuffer buffer, EGLenum bufferType, const EGLDisplay& display, EGLConfig* confPtr, EGLint* errorCode)
: m_activePainter(0)
, m_eglDisplay(display)
, m_eglSurface(EGL_NO_SURFACE)
, m_eglContext(EGL_NO_CONTEXT)
{
ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultPbufferConfig();
m_eglSurface = displayManager->createPbufferFromClientBuffer(buffer, bufferType, config, errorCode);
if (m_eglSurface == EGL_NO_SURFACE)
return;
m_eglContext = displayManager->contextForSurface(m_eglSurface);
EGLDisplayOpenVG::registerPlatformSurface(this);
}
SurfaceOpenVG::SurfaceOpenVG(EGLNativeWindowType window, const EGLDisplay& display, EGLConfig* confPtr)
: m_activePainter(0)
, m_eglDisplay(display)
, m_eglSurface(EGL_NO_SURFACE)
, m_eglContext(EGL_NO_CONTEXT)
{
ASSERT(m_eglDisplay != EGL_NO_DISPLAY);
EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(m_eglDisplay);
EGLConfig config = confPtr ? (*confPtr) : displayManager->defaultWindowConfig();
m_eglSurface = displayManager->surfaceForWindow(window, config);
ASSERT(m_eglSurface != EGL_NO_SURFACE);
m_eglContext = displayManager->contextForSurface(m_eglSurface);
EGLDisplayOpenVG::registerPlatformSurface(this);
}
// Constructor only accessible to EGLDisplayOpenVG for shared context
// initialization. The parameter types might define to void* like in the
// window surface constructor, so it can't be overloaded with all the required
// arguments and EGLDisplayOpenVG basically implements the constructor
// by itself.
SurfaceOpenVG::SurfaceOpenVG()
: m_activePainter(0)
, m_eglDisplay(EGL_NO_DISPLAY)
, m_eglSurface(EGL_NO_SURFACE)
, m_eglContext(EGL_NO_CONTEXT)
{
}
#endif
SurfaceOpenVG::~SurfaceOpenVG()
{
if (!isValid())
return;
if (m_activePainter && this == m_activePainter->baseSurface())
m_activePainter->end();
#if PLATFORM(EGL)
EGLDisplayOpenVG::forDisplay(m_eglDisplay)->destroySurface(m_eglSurface);
EGLDisplayOpenVG::unregisterPlatformSurface(this);
#else
ASSERT_NOT_REACHED();
#endif
}
bool SurfaceOpenVG::isValid() const
{
#if PLATFORM(EGL)
return (m_eglSurface != EGL_NO_SURFACE);
#else
ASSERT_NOT_REACHED();
return false;
#endif
}
int SurfaceOpenVG::width() const
{
#if PLATFORM(EGL)
ASSERT(m_eglSurface != EGL_NO_SURFACE);
EGLint width;
eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &width);
ASSERT_EGL_NO_ERROR();
return width;
#else
ASSERT_NOT_REACHED();
return 0;
#endif
}
int SurfaceOpenVG::height() const
{
#if PLATFORM(EGL)
ASSERT(m_eglSurface != EGL_NO_SURFACE);
EGLint height;
eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &height);
ASSERT_EGL_NO_ERROR();
return height;
#else
ASSERT_NOT_REACHED();
return 0;
#endif
}
SurfaceOpenVG* SurfaceOpenVG::sharedSurface() const
{
#if PLATFORM(EGL)
ASSERT(m_eglSurface != EGL_NO_SURFACE);
return EGLDisplayOpenVG::forDisplay(m_eglDisplay)->sharedPlatformSurface();
#else
ASSERT_NOT_REACHED();
return 0;
#endif
}
void SurfaceOpenVG::makeCurrent(MakeCurrentMode mode)
{
#if PLATFORM(EGL)
ASSERT(m_eglSurface != EGL_NO_SURFACE);
eglBindAPI(EGL_OPENVG_API);
ASSERT_EGL_NO_ERROR();
EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
ASSERT_EGL_NO_ERROR();
if (currentSurface != m_eglSurface) {
// Save other context before switching over.
if (s_currentPainter && mode != DontSaveOrApplyPainterState
&& s_currentPainter->surface()->m_eglSurface == currentSurface)
s_currentPainter->save(PainterOpenVG::KeepCurrentState);
eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
ASSERT_EGL_NO_ERROR();
s_currentPainter = 0;
}
#endif
if (m_activePainter && mode == ApplyPainterStateOnSurfaceSwitch
&& s_currentPainter != m_activePainter) {
m_activePainter->applyState();
s_currentPainter = m_activePainter;
}
}
void SurfaceOpenVG::makeCompatibleCurrent()
{
#if PLATFORM(EGL)
ASSERT(m_eglSurface != EGL_NO_SURFACE);
eglBindAPI(EGL_OPENVG_API);
ASSERT_EGL_NO_ERROR();
EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
ASSERT_EGL_NO_ERROR();
if (currentSurface == m_eglSurface) {
if (m_activePainter && s_currentPainter != m_activePainter) {
m_activePainter->applyState();
s_currentPainter = m_activePainter;
}
} else if (!EGLDisplayOpenVG::forDisplay(m_eglDisplay)->surfacesCompatible(currentSurface, m_eglSurface)) {
// Save other context before switching over.
if (s_currentPainter && s_currentPainter->surface()->m_eglSurface == currentSurface)
s_currentPainter->save(PainterOpenVG::KeepCurrentState);
eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
ASSERT_EGL_NO_ERROR();
s_currentPainter = 0;
}
// else: surfaces compatible, no need to switch contexts
#endif
}
void SurfaceOpenVG::flush()
{
#if PLATFORM(EGL)
ASSERT(m_eglSurface != EGL_NO_SURFACE);
eglSwapBuffers(m_eglDisplay, m_eglSurface);
ASSERT_EGL_NO_ERROR();
#endif
}
void SurfaceOpenVG::setActivePainter(PainterOpenVG* painter)
{
ASSERT(isValid());
// If painter is non-zero, we want to make sure there was no previous painter set.
ASSERT(!painter || !m_activePainter);
// Make sure a disabled painter isn't marked as global current painter anymore.
if (!painter && s_currentPainter == m_activePainter)
s_currentPainter = 0;
m_activePainter = painter;
}
PainterOpenVG* SurfaceOpenVG::activePainter()
{
ASSERT(isValid());
return m_activePainter;
}
}