Initial work

This commit is contained in:
Simon Fels 2016-05-26 22:38:57 +02:00 • committed by Simon Fels
commit 3222551702
374 changed files with 40290 additions and 0 deletions

View file

@ -0,0 +1,24 @@
# This build script corresponds to a library containing many definitions
# common to both the guest and the host. They relate to
#
LOCAL_PATH := $(call my-dir)
commonSources := \
glUtils.cpp \
ChecksumCalculator.cpp \
ChecksumCalculatorThreadInfo.cpp \
host_commonSources := $(commonSources)
host_commonLdLibs := $(CXX_STD_LIB)
### OpenglCodecCommon host ##############################################
$(call emugl-begin-host-static-library,libOpenglCodecCommon)
LOCAL_SRC_FILES := $(host_commonSources)
$(call emugl-import, libemugl_common)
$(call emugl-export,C_INCLUDES,$(EMUGL_PATH)/host/include/libOpenglRender $(LOCAL_PATH))
$(call emugl-export,LDLIBS,$(host_commonLdLibs))
$(call emugl-end-module)

View file

@ -0,0 +1,6 @@
set(SOURCES
glUtils.cpp
ChecksumCalculator.cpp
ChecksumCalculatorThreadInfo.cpp)
add_library(OpenglCodecCommon ${SOURCES})

View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2016 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.
*/
#include "ChecksumCalculator.h"
#include <string>
#include <vector>
#include <string.h>
// Checklist when implementing new protocol:
// 1. update CHECKSUMHELPER_MAX_VERSION
// 2. update maxChecksumSize()
// 3. update checksumByteSize()
// 4. update addBuffer, writeChecksum, resetChecksum, validate
// change CHECKSUMHELPER_MAX_VERSION when you want to update the protocol version
#define CHECKSUMHELPER_MAX_VERSION 1
// checksum buffer size
// Please add a new checksum buffer size when implementing a new protocol,
// as well as modifying the maxChecksumSize function.
static const size_t kV1ChecksumSize = 8;
static constexpr size_t maxChecksumSize() {
return 0 > kV1ChecksumSize ? 0 : kV1ChecksumSize;
}
static const size_t kMaxChecksumSize = maxChecksumSize();
// utility macros to create checksum string at compilation time
#define CHECKSUMHELPER_VERSION_STR_PREFIX "ANDROID_EMU_CHECKSUM_HELPER_v"
#define CHECKSUMHELPER_MACRO_TO_STR(x) #x
#define CHECKSUMHELPER_MACRO_VAL_TO_STR(x) CHECKSUMHELPER_MACRO_TO_STR(x)
static const uint32_t kMaxVersion = CHECKSUMHELPER_MAX_VERSION;
static const char* kMaxVersionStrPrefix = CHECKSUMHELPER_VERSION_STR_PREFIX;
static const char* kMaxVersionStr = CHECKSUMHELPER_VERSION_STR_PREFIX CHECKSUMHELPER_MACRO_VAL_TO_STR(CHECKSUMHELPER_MAX_VERSION);
#undef CHECKSUMHELPER_MAX_VERSION
#undef CHECKSUMHELPER_VERSION_STR_PREFIX
#undef CHECKSUMHELPER_MACRO_TO_STR
#undef CHECKSUMHELPER_MACRO_VAL_TO_STR
uint32_t ChecksumCalculator::getMaxVersion() {return kMaxVersion;}
const char* ChecksumCalculator::getMaxVersionStr() {return kMaxVersionStr;}
const char* ChecksumCalculator::getMaxVersionStrPrefix() {return kMaxVersionStrPrefix;}
bool ChecksumCalculator::setVersion(uint32_t version) {
if (version > kMaxVersion) { // unsupported version
LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Unsupported version Version %d\n",
__FUNCTION__, m_version);
return false;
}
if (m_isEncodingChecksum) { // setVersion is called in the middle of encoding checksums
LOG_CHECKSUMHELPER("%s: called between addBuffer and writeChecksum\n",
__FUNCTION__);
return false;
}
m_version = version;
LOG_CHECKSUMHELPER("%s: ChecksumCalculator Set Version %d\n", __FUNCTION__,
m_version);
return true;
}
size_t ChecksumCalculator::checksumByteSize() const {
switch (m_version) {
case 0:
return 0;
case 1:
return sizeof(uint32_t) + sizeof(m_numWrite);
default:
return 0;
}
}
void ChecksumCalculator::addBuffer(const void* buf, size_t packetLen) {
m_isEncodingChecksum = true;
switch (m_version) {
case 1:
m_v1BufferTotalLength += packetLen;
break;
}
}
bool ChecksumCalculator::writeChecksum(void* outputChecksum, size_t outputChecksumLen) {
if (outputChecksumLen < checksumByteSize()) return false;
char *checksumPtr = (char *)outputChecksum;
switch (m_version) {
case 1: { // protocol v1 is to reverse the packetLen and write it at the end
uint32_t val = computeV1Checksum();
memcpy(checksumPtr, &val, sizeof(val));
memcpy(checksumPtr+sizeof(val), &m_numWrite, sizeof(m_numWrite));
break;
}
}
resetChecksum();
m_numWrite++;
return true;
}
void ChecksumCalculator::resetChecksum() {
switch (m_version) {
case 1:
m_v1BufferTotalLength = 0;
break;
}
m_isEncodingChecksum = false;
}
bool ChecksumCalculator::validate(const void* expectedChecksum, size_t expectedChecksumLen) {
size_t checksumSize = checksumByteSize();
if (expectedChecksumLen != checksumSize) {
m_numRead++;
resetChecksum();
return false;
}
// buffers for computing the checksum
unsigned char sChecksumBuffer[kMaxChecksumSize];
switch (m_version) {
case 1: {
uint32_t val = computeV1Checksum();
memcpy(sChecksumBuffer, &val, sizeof(val));
memcpy(sChecksumBuffer+sizeof(val), &m_numRead, sizeof(m_numRead));
break;
}
}
bool isValid = !memcmp(sChecksumBuffer, expectedChecksum, checksumSize);
m_numRead++;
resetChecksum();
return isValid;
}
uint32_t ChecksumCalculator::computeV1Checksum() {
uint32_t revLen = m_v1BufferTotalLength;
revLen = (revLen & 0xffff0000) >> 16 | (revLen & 0x0000ffff) << 16;
revLen = (revLen & 0xff00ff00) >> 8 | (revLen & 0x00ff00ff) << 8;
revLen = (revLen & 0xf0f0f0f0) >> 4 | (revLen & 0x0f0f0f0f) << 4;
revLen = (revLen & 0xcccccccc) >> 2 | (revLen & 0x33333333) << 2;
revLen = (revLen & 0xaaaaaaaa) >> 1 | (revLen & 0x55555555) << 1;
return revLen;
}

View file

@ -0,0 +1,181 @@
/*
* Copyright (C) 2016 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.
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
// Set TRACE_CHECKSUMHELPER to 1 to debug creation/destruction of GLprotocol
// instances.
#define TRACE_CHECKSUMHELPER 0
#if TRACE_CHECKSUMHELPER
#define LOG_CHECKSUMHELPER(x...) fprintf(stderr, x)
#else
#define LOG_CHECKSUMHELPER(x...)
#endif
// ChecksumCalculator adds checksum as an array of bytes to GL pipe communication, which
// size depends on the protocol version. Each pipe should use one ChecksumCalculator.
// It can:
// (1) take a list of buffers one by one and compute their checksum string,
// in this case the checksum should be as the data in those buffers are
// concatenated;
// (2) compute the checksum of the buffer list, then either write them into
// a buffer provided by user, or compare it against a checksum provided
// by user
// (3) support different checksum version in future.
//
// For backward compatibility, checksum version 0 behaves the same as there is
// no checksum (i.e., checksumByteSize returns 0, validate always returns true,
// addBuffer and writeCheckSum does nothing).
//
// Notice that to detect package lost, ChecksumCalculator also keeps track of how
// many times it generates/validates checksums, and might use it as part of the
// checksum.
//
// To evaluate checksums from a list of data buffers buf1, buf2... Please call
// addBuffer(buf1, buf1len), addBuffer(buf2, buf2len) ... in order.
// Then if the checksum needs to be encoded into a buffer, one needs to allocate
// a checksum buffer with size checksumByteSize(), and call
// writeChecksum(checksumBuffer) to write the checksum to the buffer.
// If the checksum needs to be validated against an existing one, one needs to
// call validate(existChecksum, existChecksumLen).
//
// The checksum generator and validator must be set to the same version, and
// the validator must check ALL checksums in the order they are generated,
// otherwise the validation function will return false.
//
// It is allowed to change the checksum version between calculating two
// checksums. This is designed for backward compatibility reason.
//
// Example 1, encoding and decoding:
//
// bool testChecksum(void* buf, size_t bufLen) {
// // encoding message
// ChecksumCalculator encoder;
// encoder.setVersion(1);
// encoder.addBuffer(buf, bufLen);
// std::vector<unsigned char> message(bufLen + encoder.checksumByteSize());
// memcpy(&message[0], buf, bufLen);
// encoder.writeChecksum(&message[0] + bufLen, encoder.checksumByteSize());
//
// // decoding message
// ChecksumCalculator decoder;
// decoder.setVersion(1);
// decoder.addBuffer(&message[0], bufLen);
// return decoder.validate(&message[0] + bufLen, decoder.checksumByteSize());
// }
// The return value is true.
//
// Example 2, decoding will fail if the order of messages is wrong:
//
// bool testChecksumOrder(void* buf1, size_t bufLen1,
// void* buf2, size_t bufLen2) {
// // encoding messages
// ChecksumCalculator encoder;
// encoder.setVersion(1);
//
// std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize());
// std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize());
//
// encoder.addBuffer(buf1, bufLen1);
// std::vector<unsigned char> message1(bufLen1 + encoder.checksumByteSize());
// memcpy(&message1[0], buf1, bufLen1);
// encoder.writeChecksum(&message1[0] + bufLen1, encoder.checksumByteSize());
//
// encoder.addBuffer(buf2, bufLen2);
// std::vector<unsigned char> message2(bufLen2 + encoder.checksumByteSize());
// memcpy(&message2[0], buf2, bufLen2);
// encoder.writeChecksum(&message2[0] + bufLen2, encoder.checksumByteSize());
//
// // decoding messages
// ChecksumCalculator decoder;
// decoder.setVersion(1);
// decoder.addBuffer(&message2[0], bufLen2);
// // returns false because the decoding order is not consistent with
// // encoding order
// if (!decoder.validate(&message2[0]+bufLen2, decoder.checksumByteSize())) {
// return false;
// }
//
// decoder.addBuffer(&message1[0], bufLen1);
// if (!decoder.validate(&message1[0]+bufLen1, decoder.checksumByteSize())) {
// return false;
// }
//
// return false;
// }
class ChecksumCalculator {
public:
// Get and set current checksum version
uint32_t getVersion() const { return m_version; }
// Call setVersion to set a checksum version. It should be called before
// addBuffer(), writeChecksum() and validate(). And it should be called
// exact once per rendering thread if both host and guest support checksum.
// It won't be called if either host or guest does not support checksum.
bool setVersion(uint32_t version);
// Maximum supported checksum version
static uint32_t getMaxVersion();
// A version string that looks like "ANDROID_EMU_CHECKSUM_HELPER_v1"
// Used multiple times when the guest queries the maximum supported version
// from the host.
// The library owns the returned pointer. The returned pointer will be
// deconstructed when unloading library.
static const char* getMaxVersionStr();
static const char* getMaxVersionStrPrefix();
// Size of checksum in the current version
size_t checksumByteSize() const;
// Update the current checksum value from the data
// at |buf| of |bufLen| bytes. Once all buffers
// have been added, call writeChecksum() to store
// the final checksum value and reset its state.
void addBuffer(const void* buf, size_t bufLen);
// Write the checksum from the list of buffers to outputChecksum
// Will reset the list of buffers by calling resetChecksum.
// Return false if the buffer is not long enough
// Please query buffer size from checksumByteSize()
bool writeChecksum(void* outputChecksum, size_t outputChecksumLen);
// Restore the states for computing checksums.
// Automatically called at the end of writeChecksum and validate.
// Can also be used to abandon the current checksum being calculated.
// Notes: it doesn't update the internal read / write counter
void resetChecksum();
// Calculate the checksum from the list of buffers and
// compare it with the checksum encoded in expectedChecksum
// Will reset the list of buffers by calling resetChecksum.
bool validate(const void* expectedChecksum, size_t expectedChecksumLen);
protected:
uint32_t m_version = 0;
// A temporary state used to compute the total length of a list of buffers,
// if addBuffer is called.
uint32_t m_numRead = 0;
uint32_t m_numWrite = 0;
// m_isEncodingChecksum is true when between addBuffer and writeChecksum
bool m_isEncodingChecksum = false;
private:
// Compute a 32bit checksum
// Used in protocol v1
uint32_t computeV1Checksum();
// The buffer used in protocol version 1 to compute checksum.
uint32_t m_v1BufferTotalLength = 0;
};

View file

@ -0,0 +1,103 @@
/*
* Copyright (C) 2016 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.
*/
#include "ChecksumCalculatorThreadInfo.h"
#include "emugl/common/crash_reporter.h"
#include "emugl/common/lazy_instance.h"
#include "emugl/common/thread_store.h"
#include <stdio.h>
#include <atomic>
#include <string>
namespace {
class ChecksumCalculatorThreadStore : public ::emugl::ThreadStore {
public:
ChecksumCalculatorThreadStore() : ::emugl::ThreadStore(NULL) {}
};
#ifdef TRACE_CHECKSUMHELPER
std::atomic<size_t> sNumInstances(0);
#endif // TRACE_CHECKSUMHELPER
}
static ::emugl::LazyInstance<ChecksumCalculatorThreadStore> s_tls =
LAZY_INSTANCE_INIT;
static ChecksumCalculatorThreadInfo* getChecksumCalculatorThreadInfo() {
return static_cast<ChecksumCalculatorThreadInfo*>(s_tls->get());
}
ChecksumCalculatorThreadInfo::ChecksumCalculatorThreadInfo() {
LOG_CHECKSUMHELPER(
"%s: Checksum thread created (%u instances)\n", __FUNCTION__,
(size_t)sNumInstances);
s_tls->set(this);
}
ChecksumCalculatorThreadInfo::~ChecksumCalculatorThreadInfo() {
LOG_CHECKSUMHELPER(
"%s: GLprotocol destroyed (%u instances)\n", __FUNCTION__,
(size_t)sNumInstances);
s_tls->set(NULL);
}
uint32_t ChecksumCalculatorThreadInfo::getVersion() {
return getChecksumCalculatorThreadInfo()->m_protocol.getVersion();
}
bool ChecksumCalculatorThreadInfo::setVersion(uint32_t version) {
return getChecksumCalculatorThreadInfo()->m_protocol.setVersion(version);
}
size_t ChecksumCalculatorThreadInfo::checksumByteSize() {
return getChecksumCalculatorThreadInfo()->m_protocol.checksumByteSize();
}
bool ChecksumCalculatorThreadInfo::writeChecksum(void* buf,
size_t bufLen,
void* outputChecksum,
size_t outputChecksumLen) {
ChecksumCalculator& protocol =
getChecksumCalculatorThreadInfo()->m_protocol;
protocol.addBuffer(buf, bufLen);
return protocol.writeChecksum(outputChecksum, outputChecksumLen);
}
bool ChecksumCalculatorThreadInfo::validate(void* buf,
size_t bufLen,
void* checksum,
size_t checksumLen) {
ChecksumCalculator& protocol =
getChecksumCalculatorThreadInfo()->m_protocol;
protocol.addBuffer(buf, bufLen);
return protocol.validate(checksum, checksumLen);
}
void ChecksumCalculatorThreadInfo::validOrDie(void* buf,
size_t bufLen,
void* checksum,
size_t checksumLen,
const char* message) {
// We should actually call crashhandler_die(message), but I don't think we
// can link to that library from here
if (!validate(buf, bufLen, checksum, checksumLen)) {
emugl_crash_reporter(message);
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2016 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.
*/
#pragma once
#include "ChecksumCalculator.h"
// ChecksumCalculatorThreadInfo is the class that makes ChecksumCalculator
// thread-safe. On the host, please only use ChecksumCalculator through this
// class.
class ChecksumCalculatorThreadInfo {
public:
ChecksumCalculatorThreadInfo();
~ChecksumCalculatorThreadInfo();
static uint32_t getVersion();
static bool setVersion(uint32_t version);
static uint32_t getMaxVersion();
static const char* getMaxVersionString() {
return ChecksumCalculator::getMaxVersionStr();
}
static size_t checksumByteSize();
static bool writeChecksum(void* buf,
size_t bufLen,
void* outputChecksum,
size_t outputChecksumLen);
static bool validate(void* buf,
size_t bufLen,
void* checksum,
size_t checksumLen);
static void validOrDie(void* buf,
size_t bufLen,
void* checksum,
size_t checksumLen,
const char* message);
private:
ChecksumCalculator m_protocol;
};

View file

@ -0,0 +1,28 @@
/*
* Copyright (C) 2011 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.
*/
#ifndef _ERROR_LOG_H_
#define _ERROR_LOG_H_
#include <stdio.h>
#define ERR(...) fprintf(stderr, __VA_ARGS__)
#define EMUGL_DEBUG
#ifdef EMUGL_DEBUG
# define DBG(...) fprintf(stderr, __VA_ARGS__)
#else
# define DBG(...) ((void)0)
#endif
#endif // _ERROR_LOG_H_

View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2011 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.
*/
#pragma once
#include <vector>
#include <string>
#include <assert.h>
#include <string.h>
// Convenient class used to hold the common context data shared
// by both the GLESv1 and GLESv2 decoders. This corresponds to
// vertex attribute buffers.
class GLDecoderContextData {
public:
// List of supported vertex attribute indices, as they appear in
// a glVertexAttribPointer() call.
typedef enum {
VERTEX_LOCATION = 0,
NORMAL_LOCATION = 1,
COLOR_LOCATION = 2,
POINTSIZE_LOCATION = 3,
TEXCOORD0_LOCATION = 4,
TEXCOORD1_LOCATION = 5,
TEXCOORD2_LOCATION = 6,
TEXCOORD3_LOCATION = 7,
TEXCOORD4_LOCATION = 8,
TEXCOORD5_LOCATION = 9,
TEXCOORD6_LOCATION = 10,
TEXCOORD7_LOCATION = 11,
MATRIXINDEX_LOCATION = 12,
WEIGHT_LOCATION = 13,
LAST_LOCATION = 14
} PointerDataLocation;
// Default constructor.
GLDecoderContextData(int numLocations = kMaxVertexAttributes)
: mPointerData(),
mNumLocations(static_cast<unsigned>(numLocations)) {
mPointerData.resize(mNumLocations);
}
// Store |len| bytes from |data| into the buffer associated with
// vertex attribute index |loc|.
void storePointerData(unsigned int loc, void *data, size_t len) {
if (loc < mNumLocations) {
std::string& ptrData = mPointerData[loc];
ptrData.assign(reinterpret_cast<char*>(data), len);
} else {
// User error, don't do anything here
}
}
// Return pointer to data associated with vertex attribute index |loc|
void* pointerData(unsigned int loc) const {
if (loc < mNumLocations) {
return const_cast<char*>(mPointerData[loc].c_str());
} else {
// User error. Return nullptr.
return nullptr;
}
}
private:
static const int kMaxVertexAttributes = 64;
std::vector<std::string> mPointerData;
unsigned mNumLocations = 0;
};

View file

@ -0,0 +1,13 @@
ROOT=../..
include $(ROOT)/make/commondefs
CXXFILES = TcpStream.cpp GLClientState.cpp glUtils.cpp
CXXINCS += -I$(ROOT)/libs/GLESv1 -I$(ROOT)/include
LIBRARY_NAME = libcodecCommon.a
include $(COMMONRULES)

View file

@ -0,0 +1,193 @@
#ifndef EMUGL_PROTOCOL_UTILS_H
#define EMUGL_PROTOCOL_UTILS_H
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
namespace emugl {
// Helper macro
#define COMPILE_ASSERT(cond) static char kAssert##__LINE__[1 - 2 * !(cond)] __attribute__((unused)) = { 0 }
// Helper template: is_pointer.
// is_pointer<T>::value is true iff |T| is a pointer type.
template <typename T> struct is_pointer {
static const bool value = false;
};
template <typename T> struct is_pointer<T*> {
static const bool value = true;
};
// A helper template to extract values form the wire protocol stream
// and convert them to appropriate host values.
//
// The wire protocol uses 32-bit exclusively when transferring
// GLintptr or GLsizei values, as well as opaque handles like GLeglImage,
// from the guest (even when the guest is 64-bit).
//
// The corresponding host definitions depend on the host bitness. For
// example, GLintptr is 64-bit on linux-x86_64. The following is a set
// of templates that can simplify the conversion of protocol values
// into host ones.
//
// The most important one is:
//
// unpack<HOST_TYPE,SIZE_TYPE>(const void* ptr)
//
// Which reads bytes from |ptr|, using |SIZE_TYPE| as the underlying
// sized-integer specifier (e.g. 'uint32_t'), and converting the result
// into a |HOST_TYPE| value. For example:
//
// unpack<EGLImage,uint32_t>(ptr + 12);
//
// will read a 4-byte value from |ptr + 12| and convert it into
// an EGLImage, which is a host void*. The template detects host
// pointer types to perform proper type casting.
//
// TODO(digit): Add custom unpackers to handle generic opaque void* values.
// and map them to unique 32-bit values.
template <typename T, typename S, bool IS_POINTER>
struct UnpackerT {};
template <typename T, typename S>
struct UnpackerT<T,S,false> {
static inline T unpack(const void* ptr) {
COMPILE_ASSERT(sizeof(T) == sizeof(S));
return (T)(*(S*)(ptr));
}
};
template <typename T, typename S>
struct UnpackerT<T,S,true> {
static inline T unpack(const void* ptr) {
return (T)(uintptr_t)(*(S*)(ptr));
}
};
template <>
struct UnpackerT<float,uint32_t,false> {
static inline float unpack(const void* ptr) {
union {
float f;
uint32_t u;
} v;
v.u = *(uint32_t*)(ptr);
return v.f;
}
};
template <>
struct UnpackerT<double,uint64_t,false> {
static inline double unpack(const void* ptr) {
union {
double d;
uint32_t u;
} v;
v.u = *(uint64_t*)(ptr);
return v.d;
}
};
template <>
struct UnpackerT<ssize_t,uint32_t,false> {
static inline ssize_t unpack(const void* ptr) {
return (ssize_t)*(int32_t*)(ptr);
}
};
template <typename T, typename S>
inline T Unpack(const void* ptr) {
return UnpackerT<T, S, is_pointer<T>::value>::unpack(ptr);
}
// Helper class used to ensure input buffers passed to EGL/GL functions
// are properly aligned (preventing crashes with some backends).
// Usage example:
//
// InputBuffer inputBuffer(ptr, size);
// glDoStuff(inputBuffer.get());
//
// inputBuffer.get() will return the original value of |ptr| if it was
// aligned on an 8-byte boundary. Otherwise, it will return the address
// of an aligned heap-allocated copy of the original |size| bytes starting
// from |ptr|. The heap block is released at scope exit.
class InputBuffer {
public:
InputBuffer(const void* input, size_t size, size_t align = 8) :
mBuff(input), mIsCopy(false) {
if (((uintptr_t)input & (align - 1U)) != 0) {
void* newBuff = malloc(size);
memcpy(newBuff, input, size);
mBuff = newBuff;
mIsCopy = true;
}
}
~InputBuffer() {
if (mIsCopy) {
free((void*)mBuff);
}
}
const void* get() const {
return mBuff;
}
private:
const void* mBuff;
bool mIsCopy;
};
// Helper class used to ensure that output buffers passed to EGL/GL functions
// are aligned on 8-byte addresses.
// Usage example:
//
// ptr = stream->alloc(size);
// OutputBuffer outputBuffer(ptr, size);
// glGetStuff(outputBuffer.get());
// outputBuffer.flush();
//
// outputBuffer.get() returns the original value of |ptr| if it was already
// aligned on an 8=byte boundary. Otherwise, it returns the size of an heap
// allocated zeroed buffer of |size| bytes.
//
// outputBuffer.flush() copies the content of the heap allocated buffer back
// to |ptr| explictly, if needed. If a no-op if |ptr| was aligned.
class OutputBuffer {
public:
OutputBuffer(unsigned char* ptr, size_t size, size_t align = 8) :
mOrgBuff(ptr), mBuff(ptr), mSize(size) {
if (((uintptr_t)ptr & (align - 1U)) != 0) {
void* newBuff = calloc(1, size);
mBuff = newBuff;
}
}
~OutputBuffer() {
if (mBuff != mOrgBuff) {
free(mBuff);
}
}
void* get() const {
return mBuff;
}
void flush() {
if (mBuff != mOrgBuff) {
memcpy(mOrgBuff, mBuff, mSize);
}
}
private:
unsigned char* mOrgBuff;
void* mBuff;
size_t mSize;
};
} // namespace emugl
#endif // EMUGL_PROTOCOL_UTILS_H

View file

@ -0,0 +1,416 @@
/*
* Copyright (C) 2011 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.
*/
#include "glUtils.h"
#include "ErrorLog.h"
#include <string.h>
size_t glSizeof(GLenum type)
{
size_t retval = 0;
switch(type) {
case GL_BYTE:
case GL_UNSIGNED_BYTE:
retval = 1;
break;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_HALF_FLOAT_OES:
retval = 2;
break;
case GL_INT:
case GL_FLOAT:
case GL_FIXED:
case GL_BOOL:
retval = 4;
break;
#ifdef GL_DOUBLE
case GL_DOUBLE:
retval = 8;
break;
#endif
case GL_FLOAT_VEC2:
case GL_INT_VEC2:
case GL_BOOL_VEC2:
retval = 8;
break;
case GL_INT_VEC3:
case GL_BOOL_VEC3:
case GL_FLOAT_VEC3:
retval = 12;
break;
case GL_FLOAT_VEC4:
case GL_BOOL_VEC4:
case GL_INT_VEC4:
case GL_FLOAT_MAT2:
retval = 16;
break;
case GL_FLOAT_MAT3:
retval = 36;
break;
case GL_FLOAT_MAT4:
retval = 64;
break;
case GL_SAMPLER_2D:
case GL_SAMPLER_CUBE:
retval = 4;
break;
default:
ERR("**** ERROR unknown type 0x%x (%s,%d)\n", type, __FUNCTION__,__LINE__);
}
return retval;
}
size_t glUtilsParamSize(GLenum param)
{
size_t s = 0;
switch(param)
{
case GL_DEPTH_TEST:
case GL_DEPTH_FUNC:
case GL_DEPTH_BITS:
case GL_MAX_CLIP_PLANES:
case GL_GREEN_BITS:
case GL_MAX_MODELVIEW_STACK_DEPTH:
case GL_MAX_PROJECTION_STACK_DEPTH:
case GL_MAX_TEXTURE_STACK_DEPTH:
case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
case GL_MAX_TEXTURE_SIZE:
case GL_TEXTURE_GEN_MODE_OES:
case GL_TEXTURE_ENV_MODE:
case GL_FOG_MODE:
case GL_FOG_DENSITY:
case GL_FOG_START:
case GL_FOG_END:
case GL_SPOT_EXPONENT:
case GL_CONSTANT_ATTENUATION:
case GL_LINEAR_ATTENUATION:
case GL_QUADRATIC_ATTENUATION:
case GL_SHININESS:
case GL_LIGHT_MODEL_TWO_SIDE:
case GL_POINT_SIZE:
case GL_POINT_SIZE_MIN:
case GL_POINT_SIZE_MAX:
case GL_POINT_FADE_THRESHOLD_SIZE:
case GL_CULL_FACE_MODE:
case GL_FRONT_FACE:
case GL_SHADE_MODEL:
case GL_DEPTH_WRITEMASK:
case GL_DEPTH_CLEAR_VALUE:
case GL_STENCIL_FAIL:
case GL_STENCIL_PASS_DEPTH_FAIL:
case GL_STENCIL_PASS_DEPTH_PASS:
case GL_STENCIL_REF:
case GL_STENCIL_WRITEMASK:
case GL_MATRIX_MODE:
case GL_MODELVIEW_STACK_DEPTH:
case GL_PROJECTION_STACK_DEPTH:
case GL_TEXTURE_STACK_DEPTH:
case GL_ALPHA_TEST_FUNC:
case GL_ALPHA_TEST_REF:
case GL_ALPHA_TEST:
case GL_BLEND_DST:
case GL_BLEND_SRC:
case GL_BLEND:
case GL_LOGIC_OP_MODE:
case GL_SCISSOR_TEST:
case GL_MAX_TEXTURE_UNITS:
case GL_ACTIVE_TEXTURE:
case GL_ALPHA_BITS:
case GL_ARRAY_BUFFER_BINDING:
case GL_BLUE_BITS:
case GL_CLIENT_ACTIVE_TEXTURE:
case GL_CLIP_PLANE0:
case GL_CLIP_PLANE1:
case GL_CLIP_PLANE2:
case GL_CLIP_PLANE3:
case GL_CLIP_PLANE4:
case GL_CLIP_PLANE5:
case GL_COLOR_ARRAY:
case GL_COLOR_ARRAY_BUFFER_BINDING:
case GL_COLOR_ARRAY_SIZE:
case GL_COLOR_ARRAY_STRIDE:
case GL_COLOR_ARRAY_TYPE:
case GL_COLOR_LOGIC_OP:
case GL_COLOR_MATERIAL:
case GL_PACK_ALIGNMENT:
case GL_PERSPECTIVE_CORRECTION_HINT:
case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
case GL_POINT_SIZE_ARRAY_STRIDE_OES:
case GL_POINT_SIZE_ARRAY_TYPE_OES:
case GL_POINT_SMOOTH:
case GL_POINT_SMOOTH_HINT:
case GL_POINT_SPRITE_OES:
case GL_COORD_REPLACE_OES:
case GL_COMBINE_ALPHA:
case GL_SRC0_RGB:
case GL_SRC1_RGB:
case GL_SRC2_RGB:
case GL_OPERAND0_RGB:
case GL_OPERAND1_RGB:
case GL_OPERAND2_RGB:
case GL_SRC0_ALPHA:
case GL_SRC1_ALPHA:
case GL_SRC2_ALPHA:
case GL_OPERAND0_ALPHA:
case GL_OPERAND1_ALPHA:
case GL_OPERAND2_ALPHA:
case GL_RGB_SCALE:
case GL_ALPHA_SCALE:
case GL_COMBINE_RGB:
case GL_POLYGON_OFFSET_FACTOR:
case GL_POLYGON_OFFSET_FILL:
case GL_POLYGON_OFFSET_UNITS:
case GL_RED_BITS:
case GL_RESCALE_NORMAL:
case GL_SAMPLE_ALPHA_TO_COVERAGE:
case GL_SAMPLE_ALPHA_TO_ONE:
case GL_SAMPLE_BUFFERS:
case GL_SAMPLE_COVERAGE:
case GL_SAMPLE_COVERAGE_INVERT:
case GL_SAMPLE_COVERAGE_VALUE:
case GL_SAMPLES:
case GL_STENCIL_BITS:
case GL_STENCIL_CLEAR_VALUE:
case GL_STENCIL_FUNC:
case GL_STENCIL_TEST:
case GL_STENCIL_VALUE_MASK:
case GL_STENCIL_BACK_FUNC:
case GL_STENCIL_BACK_VALUE_MASK:
case GL_STENCIL_BACK_REF:
case GL_STENCIL_BACK_FAIL:
case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
case GL_STENCIL_BACK_PASS_DEPTH_PASS:
case GL_STENCIL_BACK_WRITEMASK:
case GL_TEXTURE_2D:
case GL_TEXTURE_BINDING_2D:
case GL_TEXTURE_BINDING_CUBE_MAP:
case GL_TEXTURE_BINDING_EXTERNAL_OES:
case GL_TEXTURE_COORD_ARRAY:
case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
case GL_TEXTURE_COORD_ARRAY_SIZE:
case GL_TEXTURE_COORD_ARRAY_STRIDE:
case GL_TEXTURE_COORD_ARRAY_TYPE:
case GL_UNPACK_ALIGNMENT:
case GL_VERTEX_ARRAY:
case GL_VERTEX_ARRAY_BUFFER_BINDING:
case GL_VERTEX_ARRAY_SIZE:
case GL_VERTEX_ARRAY_STRIDE:
case GL_VERTEX_ARRAY_TYPE:
case GL_SPOT_CUTOFF:
case GL_TEXTURE_MIN_FILTER:
case GL_TEXTURE_MAG_FILTER:
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_WRAP_T:
case GL_GENERATE_MIPMAP:
case GL_GENERATE_MIPMAP_HINT:
case GL_RENDERBUFFER_WIDTH_OES:
case GL_RENDERBUFFER_HEIGHT_OES:
case GL_RENDERBUFFER_INTERNAL_FORMAT_OES:
case GL_RENDERBUFFER_RED_SIZE_OES:
case GL_RENDERBUFFER_GREEN_SIZE_OES:
case GL_RENDERBUFFER_BLUE_SIZE_OES:
case GL_RENDERBUFFER_ALPHA_SIZE_OES:
case GL_RENDERBUFFER_DEPTH_SIZE_OES:
case GL_RENDERBUFFER_STENCIL_SIZE_OES:
case GL_RENDERBUFFER_BINDING:
case GL_FRAMEBUFFER_BINDING:
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES:
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES:
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES:
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES:
case GL_FENCE_STATUS_NV:
case GL_FENCE_CONDITION_NV:
case GL_TEXTURE_WIDTH_QCOM:
case GL_TEXTURE_HEIGHT_QCOM:
case GL_TEXTURE_DEPTH_QCOM:
case GL_TEXTURE_INTERNAL_FORMAT_QCOM:
case GL_TEXTURE_FORMAT_QCOM:
case GL_TEXTURE_TYPE_QCOM:
case GL_TEXTURE_IMAGE_VALID_QCOM:
case GL_TEXTURE_NUM_LEVELS_QCOM:
case GL_TEXTURE_TARGET_QCOM:
case GL_TEXTURE_OBJECT_VALID_QCOM:
case GL_BLEND_EQUATION_RGB_OES:
case GL_BLEND_EQUATION_ALPHA_OES:
case GL_BLEND_DST_RGB_OES:
case GL_BLEND_SRC_RGB_OES:
case GL_BLEND_DST_ALPHA_OES:
case GL_BLEND_SRC_ALPHA_OES:
case GL_MAX_LIGHTS:
case GL_SHADER_TYPE:
case GL_DELETE_STATUS:
case GL_COMPILE_STATUS:
case GL_INFO_LOG_LENGTH:
case GL_SHADER_SOURCE_LENGTH:
case GL_CURRENT_PROGRAM:
case GL_LINK_STATUS:
case GL_VALIDATE_STATUS:
case GL_ATTACHED_SHADERS:
case GL_ACTIVE_UNIFORMS:
case GL_ACTIVE_ATTRIBUTES:
case GL_SUBPIXEL_BITS:
case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
case GL_NUM_SHADER_BINARY_FORMATS:
case GL_SHADER_COMPILER:
case GL_MAX_VERTEX_ATTRIBS:
case GL_MAX_VERTEX_UNIFORM_VECTORS:
case GL_MAX_VARYING_VECTORS:
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
case GL_MAX_RENDERBUFFER_SIZE:
case GL_MAX_TEXTURE_IMAGE_UNITS:
case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
case GL_LINE_WIDTH:
s = 1;
break;
case GL_ALIASED_LINE_WIDTH_RANGE:
case GL_ALIASED_POINT_SIZE_RANGE:
case GL_DEPTH_RANGE:
case GL_MAX_VIEWPORT_DIMS:
case GL_SMOOTH_POINT_SIZE_RANGE:
case GL_SMOOTH_LINE_WIDTH_RANGE:
s= 2;
break;
case GL_SPOT_DIRECTION:
case GL_POINT_DISTANCE_ATTENUATION:
case GL_CURRENT_NORMAL:
s = 3;
break;
case GL_CURRENT_VERTEX_ATTRIB:
case GL_CURRENT_TEXTURE_COORDS:
case GL_CURRENT_COLOR:
case GL_FOG_COLOR:
case GL_AMBIENT:
case GL_DIFFUSE:
case GL_SPECULAR:
case GL_EMISSION:
case GL_POSITION:
case GL_LIGHT_MODEL_AMBIENT:
case GL_TEXTURE_ENV_COLOR:
case GL_SCISSOR_BOX:
case GL_VIEWPORT:
case GL_TEXTURE_CROP_RECT_OES:
case GL_COLOR_CLEAR_VALUE:
case GL_COLOR_WRITEMASK:
case GL_AMBIENT_AND_DIFFUSE:
case GL_BLEND_COLOR:
s = 4;
break;
case GL_MODELVIEW_MATRIX:
case GL_PROJECTION_MATRIX:
case GL_TEXTURE_MATRIX:
s = 16;
break;
default:
ERR("glUtilsParamSize: unknow param 0x%08x\n", param);
s = 1; // assume 1
}
return s;
}
void glUtilsPackPointerData(unsigned char *dst, unsigned char *src,
int size, GLenum type, unsigned int stride,
unsigned int datalen)
{
unsigned int vsize = size * glSizeof(type);
if (stride == 0) stride = vsize;
if (stride == vsize) {
memcpy(dst, src, datalen);
} else {
for (unsigned int i = 0; i < datalen; i += vsize) {
memcpy(dst, src, vsize);
dst += vsize;
src += stride;
}
}
}
int glUtilsPixelBitSize(GLenum format, GLenum type)
{
int components = 0;
int componentsize = 0;
int pixelsize = 0;
switch(type) {
case GL_BYTE:
case GL_UNSIGNED_BYTE:
componentsize = 8;
break;
case GL_SHORT:
case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_RGB565_OES:
case GL_RGB5_A1_OES:
case GL_RGBA4_OES:
pixelsize = 16;
break;
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
case GL_FIXED:
case GL_UNSIGNED_INT_24_8_OES:
pixelsize = 32;
break;
default:
ERR("glUtilsPixelBitSize: unknown pixel type - assuming pixel data 0\n");
componentsize = 0;
}
if (pixelsize == 0) {
switch(format) {
#if 0
case GL_RED:
case GL_GREEN:
case GL_BLUE:
#endif
case GL_ALPHA:
case GL_LUMINANCE:
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL_OES:
components = 1;
break;
case GL_LUMINANCE_ALPHA:
components = 2;
break;
case GL_RGB:
#if 0
case GL_BGR:
#endif
components = 3;
break;
case GL_RGBA:
case GL_BGRA_EXT:
components = 4;
break;
default:
ERR("glUtilsPixelBitSize: unknown pixel format...\n");
components = 0;
}
pixelsize = components * componentsize;
}
return pixelsize;
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2011 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.
*/
#pragma once
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
size_t glSizeof(GLenum type);
size_t glUtilsParamSize(GLenum param);
void glUtilsPackPointerData(unsigned char *dst, unsigned char *str,
int size, GLenum type, unsigned int stride,
unsigned int datalen);
int glUtilsPixelBitSize(GLenum format, GLenum type);
#ifdef __cplusplus
};
#endif

View file

@ -0,0 +1,62 @@
/*
* Copyright (C) 2011 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.
*/
#ifndef __GL_BASE_TYPES__H
#define __GL_BASE_TYPES__H
#include <KHR/khrplatform.h>
#ifndef gles1_APIENTRY
#define gles1_APIENTRY KHRONOS_APIENTRY
#endif
#ifndef gles2_APIENTRY
#define gles2_APIENTRY KHRONOS_APIENTRY
#endif
typedef void GLvoid;
typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef char GLchar;
typedef khronos_int8_t GLbyte;
typedef short GLshort;
typedef int GLint;
typedef int GLsizei;
typedef khronos_uint8_t GLubyte;
typedef unsigned short GLushort;
typedef unsigned int GLuint;
typedef khronos_float_t GLfloat;
typedef khronos_float_t GLclampf;
typedef khronos_int32_t GLfixed;
typedef khronos_int32_t GLclampx;
typedef khronos_intptr_t GLintptr;
typedef khronos_ssize_t GLsizeiptr;
typedef char *GLstr;
/* JR XXX Treating this as an in handle - is this correct? */
typedef void * GLeglImageOES;
/* ErrorCode */
#ifndef GL_INVALID_ENUM
#define GL_NO_ERROR 0
#define GL_INVALID_ENUM 0x0500
#define GL_INVALID_VALUE 0x0501
#define GL_INVALID_OPERATION 0x0502
#define GL_STACK_OVERFLOW 0x0503
#define GL_STACK_UNDERFLOW 0x0504
#define GL_OUT_OF_MEMORY 0x0505
#endif
#endif