/*
**
** Copyright 2007 The Android Open Source Project
**
** Licensed under the Apache License Version 2.0(the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing software
** distributed under the License is distributed on an "AS IS" BASIS
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#define LOG_TAG "EGLNativeWindowSurface"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <ui/SurfaceComposerClient.h>
#include <ui/DisplayInfo.h>
#include <ui/Rect.h>
#include <EGL/egl.h>
#include <pixelflinger/format.h>
#include <ui/EGLNativeWindowSurface.h>
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
EGLNativeWindowSurface::EGLNativeWindowSurface(const sp<Surface>& surface)
: EGLNativeSurface<EGLNativeWindowSurface>(),
mSurface(surface), mConnected(false)
{
egl_native_window_t::magic = 0x600913;
egl_native_window_t::version = sizeof(egl_native_window_t);
egl_native_window_t::ident = 0;
egl_native_window_t::incRef = &EGLNativeWindowSurface::hook_incRef;
egl_native_window_t::decRef = &EGLNativeWindowSurface::hook_decRef;
egl_native_window_t::swapBuffers = &EGLNativeWindowSurface::hook_swapBuffers;
egl_native_window_t::connect = &EGLNativeWindowSurface::hook_connect;
egl_native_window_t::disconnect = &EGLNativeWindowSurface::hook_disconnect;
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
egl_native_window_t::xdpi = dinfo.xdpi;
egl_native_window_t::ydpi = dinfo.ydpi;
egl_native_window_t::fps = dinfo.fps;
egl_native_window_t::flags= EGL_NATIVES_FLAG_DESTROY_BACKBUFFER;
}
EGLNativeWindowSurface::~EGLNativeWindowSurface()
{
disconnect();
mSurface.clear();
magic = 0;
}
void EGLNativeWindowSurface::hook_incRef(NativeWindowType window)
{
EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
that->incStrong(that);
}
void EGLNativeWindowSurface::hook_decRef(NativeWindowType window)
{
EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
that->decStrong(that);
}
void EGLNativeWindowSurface::hook_connect(NativeWindowType window)
{
EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
that->connect();
}
void EGLNativeWindowSurface::hook_disconnect(NativeWindowType window)
{
EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
that->disconnect();
}
uint32_t EGLNativeWindowSurface::hook_swapBuffers(NativeWindowType window)
{
EGLNativeWindowSurface* that = static_cast<EGLNativeWindowSurface*>(window);
return that->swapBuffers();
}
void EGLNativeWindowSurface::setSwapRectangle(int l, int t, int w, int h)
{
mSurface->setSwapRectangle(Rect(l, t, l+w, t+h));
}
uint32_t EGLNativeWindowSurface::swapBuffers()
{
const int w = egl_native_window_t::width;
const int h = egl_native_window_t::height;
const sp<Surface>& surface(mSurface);
Surface::SurfaceInfo info;
surface->unlockAndPost();
surface->lock(&info);
// update the address of the buffer to draw to next
egl_native_window_t::base = intptr_t(info.base);
egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
// update size if it changed
if (w != int(info.w) || h != int(info.h)) {
egl_native_window_t::width = info.w;
egl_native_window_t::height = info.h;
egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
egl_native_window_t::format = info.format;
return EGL_NATIVES_FLAG_SIZE_CHANGED;
}
return 0;
}
void EGLNativeWindowSurface::connect()
{
if (!mConnected) {
Surface::SurfaceInfo info;
mSurface->lock(&info);
mSurface->setSwapRectangle(Rect(info.w, info.h));
mConnected = true;
egl_native_window_t::width = info.w;
egl_native_window_t::height = info.h;
egl_native_window_t::stride = info.bpr / bytesPerPixel(info.format);
egl_native_window_t::format = info.format;
egl_native_window_t::base = intptr_t(info.base);
egl_native_window_t::offset = intptr_t(info.bits) - intptr_t(info.base);
// FIXME: egl_native_window_t::memory_type used to be set from
// mSurface, but we wanted to break this dependency. We set it to
// GPU because the software rendered doesn't care, but the h/w
// accelerator needs it. Eventually, this value should go away
// completely, since memory will be managed by OpenGL.
egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_GPU;
egl_native_window_t::fd = 0;
}
}
void EGLNativeWindowSurface::disconnect()
{
if (mConnected) {
mSurface->unlock();
mConnected = false;
}
}
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------