213 lines
6.7 KiB
C++
213 lines
6.7 KiB
C++
/*
|
|
* Copyright 2010, The Android Open Source Project
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include "RenderingThread.h"
|
|
|
|
#include "ANPNativeWindow_npapi.h"
|
|
|
|
#include <android/native_window.h>
|
|
|
|
extern ANPLogInterfaceV0 gLogI;
|
|
extern ANPNativeWindowInterfaceV0 gNativeWindowI;
|
|
|
|
RenderingThread::RenderingThread(NPP npp) : android::Thread() {
|
|
m_npp = npp;
|
|
m_width = -1;
|
|
m_height = -1;
|
|
|
|
m_ANW = NULL;
|
|
#if (!USE_SOFTWARE_RENDERING)
|
|
m_eglSurface = EGL_NO_SURFACE;
|
|
m_eglContext = EGL_NO_CONTEXT;
|
|
m_eglDisplay = EGL_NO_DISPLAY;
|
|
#endif
|
|
}
|
|
|
|
android::status_t RenderingThread::readyToRun() {
|
|
gLogI.log(kError_ANPLogType, "thread %p acquiring native window...", this);
|
|
while (m_ANW == NULL) {
|
|
m_ANW = gNativeWindowI.acquireNativeWindow(m_npp);
|
|
if (!m_ANW)
|
|
gLogI.log(kError_ANPLogType, "thread %p acquire native window FAILED!", this);
|
|
|
|
}
|
|
gLogI.log(kError_ANPLogType, "thread %p acquired native window successfully!", this);
|
|
|
|
#if (!USE_SOFTWARE_RENDERING)
|
|
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
|
|
//initialize context
|
|
EGLint numConfigs;
|
|
static const EGLint configAttribs[] = {
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
EGL_RED_SIZE, 8,
|
|
EGL_GREEN_SIZE, 8,
|
|
EGL_BLUE_SIZE, 8,
|
|
EGL_ALPHA_SIZE, 8,
|
|
EGL_NONE
|
|
};
|
|
|
|
eglChooseConfig(m_eglDisplay, configAttribs, &m_eglConfig, 1, &numConfigs);
|
|
checkGlError("eglChooseConfig");
|
|
|
|
static const EGLint contextAttribs[] = {
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
EGL_NONE
|
|
};
|
|
|
|
m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttribs);
|
|
checkGlError("eglCreateContext");
|
|
#endif
|
|
|
|
return android::NO_ERROR;
|
|
}
|
|
|
|
void RenderingThread::setDimensions(int width, int height) {
|
|
android::Mutex::Autolock lock(m_sync);
|
|
m_width = width;
|
|
m_height = height;
|
|
}
|
|
|
|
void RenderingThread::getDimensions(int& width, int& height) {
|
|
android::Mutex::Autolock lock(m_sync);
|
|
width = m_width;
|
|
height = m_height;
|
|
}
|
|
|
|
void RenderingThread::printGLString(const char *name, GLenum s) {
|
|
const char *v = (const char *) glGetString(s);
|
|
gLogI.log(kError_ANPLogType, "GL %s = %s\n", name, v);
|
|
}
|
|
|
|
void RenderingThread::checkGlError(const char* op) {
|
|
for (GLint error = glGetError(); error; error
|
|
= glGetError()) {
|
|
gLogI.log(kError_ANPLogType, "after %s() glError (0x%x)\n", op, error);
|
|
}
|
|
}
|
|
|
|
GLenum RenderingThread::getInternalFormat(SkBitmap::Config config)
|
|
{
|
|
switch(config) {
|
|
case SkBitmap::kA8_Config:
|
|
return GL_ALPHA;
|
|
case SkBitmap::kARGB_4444_Config:
|
|
return GL_RGBA;
|
|
case SkBitmap::kARGB_8888_Config:
|
|
return GL_RGBA;
|
|
case SkBitmap::kRGB_565_Config:
|
|
return GL_RGB;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
GLenum RenderingThread::getType(SkBitmap::Config config)
|
|
{
|
|
switch(config) {
|
|
case SkBitmap::kA8_Config:
|
|
return GL_UNSIGNED_BYTE;
|
|
case SkBitmap::kARGB_4444_Config:
|
|
return GL_UNSIGNED_SHORT_4_4_4_4;
|
|
case SkBitmap::kARGB_8888_Config:
|
|
return GL_UNSIGNED_BYTE;
|
|
case SkBitmap::kIndex8_Config:
|
|
return -1; // No type for compressed data.
|
|
case SkBitmap::kRGB_565_Config:
|
|
return GL_UNSIGNED_SHORT_5_6_5;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void RenderingThread::setupNativeWindow(ANativeWindow* ANW, const SkBitmap& bitmap)
|
|
{
|
|
int result = ANativeWindow_setBuffersGeometry(ANW, bitmap.width(),
|
|
bitmap.height(), WINDOW_FORMAT_RGBA_8888);
|
|
|
|
if (android::NO_ERROR != result) {
|
|
gLogI.log(kError_ANPLogType, "ERROR setBuffersGeometry() status is (%d)", result);
|
|
}
|
|
|
|
#if (!USE_SOFTWARE_RENDERING)
|
|
if (m_eglSurface != EGL_NO_SURFACE) {
|
|
gLogI.log(kDebug_ANPLogType, "destroying old surface");
|
|
eglDestroySurface(m_eglDisplay, m_eglSurface);
|
|
}
|
|
|
|
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, ANW, NULL);
|
|
checkGlError("eglCreateWindowSurface");
|
|
|
|
eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
|
|
|
|
//optional: enable async mode
|
|
//eglSwapInterval(m_eglDisplay, 0);
|
|
#endif
|
|
|
|
updateNativeWindow(ANW, bitmap);
|
|
}
|
|
|
|
void RenderingThread::updateNativeWindow(ANativeWindow* ANW,
|
|
const SkBitmap& bitmap)
|
|
{
|
|
#if USE_SOFTWARE_RENDERING
|
|
if (bitmap.height() == 0 || bitmap.width() == 0)
|
|
return;
|
|
|
|
//STEP 1: lock the ANW, getting a buffer
|
|
ANativeWindow_Buffer buffer;
|
|
if (ANativeWindow_lock(ANW, &buffer, NULL) < 0 ) // todo: use rect parameter for efficiency
|
|
return;
|
|
|
|
//STEP 2: draw into the buffer
|
|
uint8_t* img = (uint8_t*)buffer.bits;
|
|
int row, col;
|
|
int bpp = 4; // Here we only deal with RGBA8888 format.
|
|
bitmap.lockPixels();
|
|
uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
|
|
// Copy line by line to handle offsets and stride
|
|
for (row = 0 ; row < bitmap.height(); row ++) {
|
|
uint8_t* dst = &(img[(buffer.stride * (row + 0) + 0) * bpp]);
|
|
uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
|
|
memcpy(dst, src, bpp * bitmap.width());
|
|
}
|
|
bitmap.unlockPixels();
|
|
|
|
//STEP 3: push the buffer to the queue
|
|
ANativeWindow_unlockAndPost(ANW);
|
|
|
|
#else
|
|
|
|
//rotate the intensity of the green channel, other channels fixed
|
|
static int i = 0;
|
|
i = (i >= 245) ? 0 : i+10;
|
|
|
|
glClearColor(0.6, (i*1.0/256), 0.6, 0.6);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
eglSwapBuffers(m_eglDisplay, m_eglSurface);
|
|
#endif
|
|
}
|
|
|