$(call emugl-import,libGLESv1_enc libGLESv2_enc lib_renderControl_enc)
LOCAL_SRC_FILES := \
+ goldfish_dma.cpp \
+ FormatConversions.cpp \
HostConnection.cpp \
ProcessPipe.cpp \
QemuPipeStream.cpp \
--- /dev/null
+/*
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#include "FormatConversions.h"
+
+#include <cutils/log.h>
+#include <string.h>
+
+#define DEBUG 0
+
+#if DEBUG
+#define DD(...) ALOGD(...)
+#else
+#define DD(...)
+#endif
+
+void get_yv12_offsets(int width, int height,
+ uint32_t* yStride_out,
+ uint32_t* cStride_out,
+ uint32_t* totalSz_out) {
+ uint32_t align = 16;
+ uint32_t yStride = (width + (align - 1)) & ~(align-1);
+ uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1);
+ uint32_t uvHeight = height / 2;
+ uint32_t sz = yStride * height + 2 * (uvHeight * uvStride);
+
+ if (yStride_out) *yStride_out = yStride;
+ if (cStride_out) *cStride_out = uvStride;
+ if (totalSz_out) *totalSz_out = sz;
+}
+
+void get_yuv420p_offsets(int width, int height,
+ uint32_t* yStride_out,
+ uint32_t* cStride_out,
+ uint32_t* totalSz_out) {
+ uint32_t align = 1;
+ uint32_t yStride = (width + (align - 1)) & ~(align-1);
+ uint32_t uvStride = (yStride / 2 + (align - 1)) & ~(align-1);
+ uint32_t uvHeight = height / 2;
+ uint32_t sz = yStride * height + 2 * (uvHeight * uvStride);
+
+ if (yStride_out) *yStride_out = yStride;
+ if (cStride_out) *cStride_out = uvStride;
+ if (totalSz_out) *totalSz_out = sz;
+}
+
+signed clamp_rgb(signed value) {
+ if (value > 255) {
+ value = 255;
+ } else if (value < 0) {
+ value = 0;
+ }
+ return value;
+}
+
+void rgb565_to_yv12(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom) {
+ int align = 16;
+ int yStride = (width + (align -1)) & ~(align-1);
+ int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
+ int yOffset = 0;
+ int cSize = cStride * height/2;
+
+ uint16_t *rgb_ptr0 = (uint16_t *)src;
+ uint8_t *yv12_y0 = (uint8_t *)dest;
+ uint8_t *yv12_v0 = yv12_y0 + yStride * height;
+ uint8_t *yv12_u0 = yv12_v0 + cSize;
+
+ for (int j = top; j <= bottom; ++j) {
+ uint8_t *yv12_y = yv12_y0 + j * yStride;
+ uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
+ uint8_t *yv12_u = yv12_v + cSize;
+ uint16_t *rgb_ptr = rgb_ptr0 + j * width;
+ bool jeven = (j & 1) == 0;
+ for (int i = left; i <= right; ++i) {
+ uint8_t r = ((rgb_ptr[i]) >> 11) & 0x01f;
+ uint8_t g = ((rgb_ptr[i]) >> 5) & 0x03f;
+ uint8_t b = (rgb_ptr[i]) & 0x01f;
+ // convert to 8bits
+ // http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888
+ uint8_t R = (r * 527 + 23) >> 6;
+ uint8_t G = (g * 259 + 33) >> 6;
+ uint8_t B = (b * 527 + 23) >> 6;
+ // convert to YV12
+ // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+ yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
+ bool ieven = (i & 1) == 0;
+ if (jeven && ieven) {
+ yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
+ yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
+ }
+ }
+ }
+}
+
+void rgb888_to_yv12(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom) {
+ DD("%s convert %d by %d", __func__, width, height);
+ int align = 16;
+ int yStride = (width + (align -1)) & ~(align-1);
+ int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
+ int yOffset = 0;
+ int cSize = cStride * height/2;
+ int rgb_stride = 3;
+
+ uint8_t *rgb_ptr0 = (uint8_t *)src;
+ uint8_t *yv12_y0 = (uint8_t *)dest;
+ uint8_t *yv12_v0 = yv12_y0 + yStride * height;
+ uint8_t *yv12_u0 = yv12_v0 + cSize;
+
+ for (int j = top; j <= bottom; ++j) {
+ uint8_t *yv12_y = yv12_y0 + j * yStride;
+ uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
+ uint8_t *yv12_u = yv12_v + cSize;
+ uint8_t *rgb_ptr = rgb_ptr0 + j * width*rgb_stride;
+ bool jeven = (j & 1) == 0;
+ for (int i = left; i <= right; ++i) {
+ uint8_t R = rgb_ptr[i*rgb_stride];
+ uint8_t G = rgb_ptr[i*rgb_stride+1];
+ uint8_t B = rgb_ptr[i*rgb_stride+2];
+ // convert to YV12
+ // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+ yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
+ bool ieven = (i & 1) == 0;
+ if (jeven && ieven) {
+ yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
+ yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
+ }
+ }
+ }
+}
+
+void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom) {
+ DD("%s convert %d by %d", __func__, width, height);
+ int yStride = width;
+ int cStride = yStride / 2;
+ int yOffset = 0;
+ int cSize = cStride * height/2;
+ int rgb_stride = 3;
+
+ uint8_t *rgb_ptr0 = (uint8_t *)src;
+ uint8_t *yv12_y0 = (uint8_t *)dest;
+ uint8_t *yv12_u0 = yv12_y0 + yStride * height;
+ uint8_t *yv12_v0 = yv12_u0 + cSize;
+
+ for (int j = top; j <= bottom; ++j) {
+ uint8_t *yv12_y = yv12_y0 + j * yStride;
+ uint8_t *yv12_u = yv12_u0 + (j/2) * cStride;
+ uint8_t *yv12_v = yv12_u + cStride;
+ uint8_t *rgb_ptr = rgb_ptr0 + j * width*rgb_stride;
+ bool jeven = (j & 1) == 0;
+ for (int i = left; i <= right; ++i) {
+ uint8_t R = rgb_ptr[i*rgb_stride];
+ uint8_t G = rgb_ptr[i*rgb_stride+1];
+ uint8_t B = rgb_ptr[i*rgb_stride+2];
+ // convert to YV12
+ // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+ yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
+ bool ieven = (i & 1) == 0;
+ if (jeven && ieven) {
+ yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
+ yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
+ }
+ }
+ }
+}
+// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
+// certain stride requirements for Y and UV respectively.
+void yv12_to_rgb565(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom) {
+ DD("%s convert %d by %d", __func__, width, height);
+ int align = 16;
+ int yStride = (width + (align -1)) & ~(align-1);
+ int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
+ int yOffset = 0;
+ int cSize = cStride * height/2;
+
+ uint16_t *rgb_ptr0 = (uint16_t *)dest;
+ uint8_t *yv12_y0 = (uint8_t *)src;
+ uint8_t *yv12_v0 = yv12_y0 + yStride * height;
+ uint8_t *yv12_u0 = yv12_v0 + cSize;
+
+ for (int j = top; j <= bottom; ++j) {
+ uint8_t *yv12_y = yv12_y0 + j * yStride;
+ uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
+ uint8_t *yv12_u = yv12_v + cSize;
+ uint16_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1);
+ for (int i = left; i <= right; ++i) {
+ // convert to rgb
+ // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
+ signed y1 = (signed)yv12_y[i] - 16;
+ signed u = (signed)yv12_u[i / 2] - 128;
+ signed v = (signed)yv12_v[i / 2] - 128;
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = clamp_rgb((tmp1 + u_b) / 256);
+ signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
+ signed r1 = clamp_rgb((tmp1 + v_r) / 256);
+
+ uint16_t rgb1 = ((r1 >> 3) << 11) | ((g1 >> 2) << 5) | (b1 >> 3);
+
+ rgb_ptr[i-left] = rgb1;
+ }
+ }
+}
+
+// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
+// certain stride requirements for Y and UV respectively.
+void yv12_to_rgb888(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom) {
+ DD("%s convert %d by %d", __func__, width, height);
+ int align = 16;
+ int yStride = (width + (align -1)) & ~(align-1);
+ int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
+ int yOffset = 0;
+ int cSize = cStride * height/2;
+ int rgb_stride = 3;
+
+ uint8_t *rgb_ptr0 = (uint8_t *)dest;
+ uint8_t *yv12_y0 = (uint8_t *)src;
+ uint8_t *yv12_v0 = yv12_y0 + yStride * height;
+ uint8_t *yv12_u0 = yv12_v0 + cSize;
+
+ for (int j = top; j <= bottom; ++j) {
+ uint8_t *yv12_y = yv12_y0 + j * yStride;
+ uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
+ uint8_t *yv12_u = yv12_v + cSize;
+ uint8_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1) * rgb_stride;
+ for (int i = left; i <= right; ++i) {
+ // convert to rgb
+ // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
+ signed y1 = (signed)yv12_y[i] - 16;
+ signed u = (signed)yv12_u[i / 2] - 128;
+ signed v = (signed)yv12_v[i / 2] - 128;
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = clamp_rgb((tmp1 + u_b) / 256);
+ signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
+ signed r1 = clamp_rgb((tmp1 + v_r) / 256);
+
+ rgb_ptr[(i-left)*rgb_stride] = r1;
+ rgb_ptr[(i-left)*rgb_stride+1] = g1;
+ rgb_ptr[(i-left)*rgb_stride+2] = b1;
+ }
+ }
+}
+
+// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
+// certain stride requirements for Y and UV respectively.
+void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom) {
+ DD("%s convert %d by %d", __func__, width, height);
+ int yStride = width;
+ int cStride = yStride / 2;
+ int yOffset = 0;
+ int cSize = cStride * height/2;
+ int rgb_stride = 3;
+
+ uint8_t *rgb_ptr0 = (uint8_t *)dest;
+ uint8_t *yv12_y0 = (uint8_t *)src;
+ uint8_t *yv12_u0 = yv12_y0 + yStride * height;
+ uint8_t *yv12_v0 = yv12_u0 + cSize;
+
+ for (int j = top; j <= bottom; ++j) {
+ uint8_t *yv12_y = yv12_y0 + j * yStride;
+ uint8_t *yv12_u = yv12_u0 + (j/2) * cStride;
+ uint8_t *yv12_v = yv12_u + cSize;
+ uint8_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1) * rgb_stride;
+ for (int i = left; i <= right; ++i) {
+ // convert to rgb
+ // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
+ signed y1 = (signed)yv12_y[i] - 16;
+ signed u = (signed)yv12_u[i / 2] - 128;
+ signed v = (signed)yv12_v[i / 2] - 128;
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = clamp_rgb((tmp1 + u_b) / 256);
+ signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
+ signed r1 = clamp_rgb((tmp1 + v_r) / 256);
+
+ rgb_ptr[(i-left)*rgb_stride] = r1;
+ rgb_ptr[(i-left)*rgb_stride+1] = g1;
+ rgb_ptr[(i-left)*rgb_stride+2] = b1;
+ }
+ }
+}
+
+void copy_rgb_buffer(char* _dst, char* raw_data,
+ int width, int height, int top, int left,
+ int bpp) {
+ char* dst = _dst;
+ int dst_line_len = width * bpp;
+ int src_line_len = width * bpp;
+ char *src = (char *)raw_data + top*src_line_len + left*bpp;
+ for (int y = 0; y < height; y++)
+ memcpy(dst, src, dst_line_len);
+ src += src_line_len;
+ dst += dst_line_len;
+}
--- /dev/null
+/*
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#ifndef __GOLDFISH_FORMATCONVERSIONS_H__
+#define __GOLDFISH_FORMATCONVERSIONS_H__
+
+#include <inttypes.h>
+
+// format conversions and helper functions
+void get_yv12_offsets(int width, int height,
+ uint32_t* yStride_out,
+ uint32_t* cStride_out,
+ uint32_t* totalSz_out);
+void get_yuv420p_offsets(int width, int height,
+ uint32_t* yStride_out,
+ uint32_t* cStride_out,
+ uint32_t* totalSz_out);
+signed clamp_rgb(signed value);
+void rgb565_to_yv12(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom);
+void rgb888_to_yv12(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom);
+void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom);
+void yv12_to_rgb565(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom);
+void yv12_to_rgb888(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom);
+void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
+ int left, int top, int right, int bottom);
+void copy_rgb_buffer(char* _dst, char* raw_data,
+ int width, int height, int top, int left,
+ int bpp);
+#endif
return NULL;
}
con->m_stream = stream;
+ con->m_pipeFd = stream->getSocket();
}
else /* !useQemuPipe */
{
m_rcEnc = new ExtendedRCEncoderContext(m_stream, checksumHelper());
setChecksumHelper(m_rcEnc);
queryAndSetSyncImpl(m_rcEnc);
+ queryAndSetDmaImpl(m_rcEnc);
processPipeInit(m_rcEnc);
}
return m_rcEnc;
}
#endif
}
+
+void HostConnection::queryAndSetDmaImpl(ExtendedRCEncoderContext *rcEnc) {
+ std::string glExtensions = queryGLExtensions(rcEnc);
+#if PLATFORM_SDK_VERSION <= 16 || (!defined(__i386__) && !defined(__x86_64__))
+ rcEnc->setDmaImpl(DMA_IMPL_NONE);
+#else
+ if (glExtensions.find(kDmaExtStr_v1) != std::string::npos) {
+ rcEnc->setDmaImpl(DMA_IMPL_v1);
+ } else {
+ rcEnc->setDmaImpl(DMA_IMPL_NONE);
+ }
+#endif
+}
#include "IOStream.h"
#include "renderControl_enc.h"
#include "ChecksumCalculator.h"
+#include "goldfish_dma.h"
#include <string>
SYNC_IMPL_NONE = 0,
SYNC_IMPL_NATIVE_SYNC = 1
};
+
// Interface:
// If this GL extension string shows up, we use
// SYNC_IMPL_NATIVE_SYNC, otherwise we use SYNC_IMPL_NONE.
// otherwise, we do not use the feature.
static const char kRCNativeSync[] = "ANDROID_EMU_native_sync_v2";
+// DMA for OpenGL
+enum DmaImpl {
+ DMA_IMPL_NONE = 0,
+ DMA_IMPL_v1 = 1,
+};
+
+static const char kDmaExtStr_v1[] = "ANDROID_EMU_dma_v1";
+
// ExtendedRCEncoderContext is an extended version of renderControl_encoder_context_t
// that will be used to track SyncImpl.
class ExtendedRCEncoderContext : public renderControl_encoder_context_t {
public:
ExtendedRCEncoderContext(IOStream *stream, ChecksumCalculator *checksumCalculator)
- : renderControl_encoder_context_t(stream, checksumCalculator) { }
+ : renderControl_encoder_context_t(stream, checksumCalculator) {
+ m_dmaCxt = NULL;
+ }
void setSyncImpl(SyncImpl syncImpl) { m_syncImpl = syncImpl; }
+ void setDmaImpl(DmaImpl dmaImpl) { m_dmaImpl = dmaImpl; }
bool hasNativeSync() const { return m_syncImpl == SYNC_IMPL_NATIVE_SYNC; }
+ DmaImpl getDmaVersion() const { return m_dmaImpl; }
+ void bindDmaContext(struct goldfish_dma_context* cxt) { m_dmaCxt = cxt; }
+ virtual uint64_t lockAndWriteDma(void* data, uint32_t size) {
+ ALOGV("%s: call", __FUNCTION__);
+ if (!m_dmaCxt) {
+ ALOGE("%s: ERROR: No DMA context bound!",
+ __FUNCTION__);
+ return 0;
+ }
+ goldfish_dma_lock(m_dmaCxt);
+ goldfish_dma_write(m_dmaCxt, data, size);
+ uint64_t paddr = goldfish_dma_guest_paddr(m_dmaCxt);
+ ALOGV("%s: paddr=0x%llx", __FUNCTION__, paddr);
+ return paddr;
+ }
private:
SyncImpl m_syncImpl;
+ DmaImpl m_dmaImpl;
+ struct goldfish_dma_context* m_dmaCxt;
};
class HostConnection
bool isGrallocOnly() const { return m_grallocOnly; }
+ int getPipeFd() const { return m_pipeFd; }
+
private:
HostConnection();
static gl_client_context_t *s_getGLContext();
// should be called when m_rcEnc is created
void setChecksumHelper(ExtendedRCEncoderContext *rcEnc);
void queryAndSetSyncImpl(ExtendedRCEncoderContext *rcEnc);
+ void queryAndSetDmaImpl(ExtendedRCEncoderContext *rcEnc);
private:
IOStream *m_stream;
ChecksumCalculator m_checksumHelper;
std::string m_glExtensions;
bool m_grallocOnly;
+ int m_pipeFd;
};
#endif
*/
#include "renderControl_enc.h"
+#include "qemu_pipe.h"
#include <cutils/log.h>
#include <pthread.h>
-#if PLATFORM_SDK_VERSION > 24
-#include <system/qemu_pipe.h>
-#else // PLATFORM_SDK_VERSION
-#include <hardware/qemu_pipe.h>
-#endif //PLATFORM_SDK_VERSION
static int sProcPipe = 0;
static pthread_once_t sProcPipeOnce = PTHREAD_ONCE_INIT;
if (!sProcPipe) return false;
rcEnc->rcSetPuid(rcEnc, sProcUID);
return true;
-}
\ No newline at end of file
+}
* limitations under the License.
*/
#include "QemuPipeStream.h"
-#if PLATFORM_SDK_VERSION > 24
-#include <system/qemu_pipe.h>
-#else // PLATFORM_SDK_VERSION
-#include <hardware/qemu_pipe.h>
-#endif //PLATFORM_SDK_VERSION
+#include "qemu_pipe.h"
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#else // PLATFORM_SDK_VERSION
m_sock = qemu_pipe_open("opengles");
#endif // PLATFORM_SDK_VERSION
- if (!valid()) return -1;
+ if (!valid()) {
+ ALOGE("%s: failed with fd %d errno %d", __FUNCTION__, m_sock, errno);
+ return -1;
+ }
return 0;
}
return retval;
}
+int QemuPipeStream::getSocket() const {
+ return m_sock;
+}
+
const unsigned char *QemuPipeStream::readFully(void *buf, size_t len)
{
//DBG(">> QemuPipeStream::readFully %d\n", len);
virtual int writeFully(const void *buf, size_t len);
+ int getSocket() const;
private:
int m_sock;
size_t m_bufsize;
--- /dev/null
+/*
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#include "goldfish_dma.h"
+#include "qemu_pipe.h"
+
+#include <cutils/log.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+
+int goldfish_dma_lock(struct goldfish_dma_context* cxt) {
+ struct goldfish_dma_ioctl_info info;
+
+ return ioctl(cxt->fd, GOLDFISH_DMA_IOC_LOCK, &info);
+}
+
+int goldfish_dma_unlock(struct goldfish_dma_context* cxt) {
+ struct goldfish_dma_ioctl_info info;
+
+ return ioctl(cxt->fd, GOLDFISH_DMA_IOC_UNLOCK, &info);
+}
+
+int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res) {
+
+ res->fd = qemu_pipe_open("opengles");
+ res->mapped = NULL;
+ res->sz = 0;
+
+ if (res->fd > 0) {
+ // now alloc
+ struct goldfish_dma_ioctl_info info;
+ info.size = sz;
+ int alloc_res = ioctl(res->fd, GOLDFISH_DMA_IOC_CREATE_REGION, &info);
+
+ if (alloc_res) {
+ ALOGE("%s: failed to allocate DMA region. errno=%d",
+ __FUNCTION__, errno);
+ close(res->fd);
+ res->fd = -1;
+ return alloc_res;
+ }
+
+ res->sz = sz;
+ ALOGV("%s: successfully allocated goldfish DMA region with size %lu cxt=%p",
+ __FUNCTION__, sz, res);
+ return 0;
+ } else {
+ ALOGE("%s: could not obtain fd to device! fd %d errno=%d\n",
+ __FUNCTION__, res->fd, errno);
+ return ENODEV;
+ }
+}
+
+void* goldfish_dma_map(struct goldfish_dma_context* cxt) {
+ ALOGV("%s: on fd %d errno=%d", __FUNCTION__, cxt->fd, errno);
+ cxt->mapped = mmap(0, cxt->sz, PROT_WRITE, MAP_SHARED, cxt->fd, 0);
+ ALOGV("%s: mapped addr=%p errno=%d", __FUNCTION__, cxt->mapped, errno);
+
+ if (cxt->mapped == MAP_FAILED) {
+ cxt->mapped = NULL;
+ }
+ return cxt->mapped;
+}
+
+int goldfish_dma_unmap(struct goldfish_dma_context* cxt) {
+ munmap(cxt->mapped, cxt->sz);
+ cxt->mapped = NULL;
+ cxt->sz = 0;
+ return 0;
+}
+
+void goldfish_dma_write(struct goldfish_dma_context* cxt,
+ void* to_write,
+ uint32_t sz) {
+ ALOGV("%s: mapped addr=%p", __FUNCTION__, cxt->mapped);
+ memcpy(cxt->mapped, to_write, sz);
+}
+
+void goldfish_dma_free(goldfish_dma_context* cxt) {
+ struct goldfish_dma_ioctl_info info;
+ close(cxt->fd);
+}
+
+uint64_t goldfish_dma_guest_paddr(struct goldfish_dma_context* cxt) {
+ struct goldfish_dma_ioctl_info info;
+ ioctl(cxt->fd, GOLDFISH_DMA_IOC_GETOFF, &info);
+ return info.phys_begin;
+}
--- /dev/null
+/*
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#ifndef ANDROID_INCLUDE_HARDWARE_GOLDFISH_DMA_H
+#define ANDROID_INCLUDE_HARDWARE_GOLDFISH_DMA_H
+
+#include <errno.h>
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <sys/cdefs.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+/* There is an ioctl associated with goldfish dma driver.
+ * Make it conflict with ioctls that are not likely to be used
+ * in the emulator.
+ * 'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict!
+ * 'G' 00-0F linux/gigaset_dev.h conflict!
+ */
+#define GOLDFISH_DMA_IOC_MAGIC 'G'
+
+#define GOLDFISH_DMA_IOC_LOCK _IOWR(GOLDFISH_DMA_IOC_MAGIC, 0, struct goldfish_dma_ioctl_info)
+#define GOLDFISH_DMA_IOC_UNLOCK _IOWR(GOLDFISH_DMA_IOC_MAGIC, 1, struct goldfish_dma_ioctl_info)
+#define GOLDFISH_DMA_IOC_GETOFF _IOWR(GOLDFISH_DMA_IOC_MAGIC, 2, struct goldfish_dma_ioctl_info)
+#define GOLDFISH_DMA_IOC_CREATE_REGION _IOWR(GOLDFISH_DMA_IOC_MAGIC, 3, struct goldfish_dma_ioctl_info)
+
+struct goldfish_dma_ioctl_info {
+ uint64_t phys_begin;
+ uint64_t size;
+};
+
+// userspace interface
+struct goldfish_dma_context {
+ int fd;
+ void* mapped;
+ uint64_t sz; // size of reservation
+};
+
+int goldfish_dma_lock(struct goldfish_dma_context* cxt);
+int goldfish_dma_unlock(struct goldfish_dma_context* cxt);
+int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res);
+
+void* goldfish_dma_map(struct goldfish_dma_context* cxt);
+int goldfish_dma_unmap(struct goldfish_dma_context* cxt);
+
+void goldfish_dma_write(struct goldfish_dma_context* cxt,
+ void* to_write,
+ uint32_t sz);
+
+void goldfish_dma_free(goldfish_dma_context* cxt);
+uint64_t goldfish_dma_guest_paddr(struct goldfish_dma_context* cxt);
+
+#endif
#include <hardware/gralloc.h>
#include <cutils/native_handle.h>
+#include "goldfish_dma.h"
+
#define BUFFER_HANDLE_MAGIC ((int)0xabfabfab)
#define CB_HANDLE_NUM_INTS(nfds) (int)((sizeof(cb_handle_t) - (nfds)*sizeof(int)) / sizeof(int))
+// Tell the emulator which gralloc formats
+// need special handling.
+enum EmulatorFrameworkFormat {
+ FRAMEWORK_FORMAT_GL_COMPATIBLE = 0,
+ FRAMEWORK_FORMAT_YV12 = 1,
+ FRAMEWORK_FORMAT_YUV_420_888 = 2,
+};
+
//
// Our buffer handle structure
//
cb_handle_t(int p_fd, int p_ashmemSize, int p_usage,
int p_width, int p_height, int p_frameworkFormat,
- int p_format, int p_glFormat, int p_glType) :
+ int p_format, int p_glFormat, int p_glType,
+ EmulatorFrameworkFormat p_emuFrameworkFormat) :
fd(p_fd),
magic(BUFFER_HANDLE_MAGIC),
usage(p_usage),
lockedTop(0),
lockedWidth(0),
lockedHeight(0),
- hostHandle(0)
+ hostHandle(0),
+ emuFrameworkFormat(p_emuFrameworkFormat)
{
+ goldfish_dma.fd = -1;
+ dmafd = -1;
version = sizeof(native_handle);
numFds = 0;
numInts = CB_HANDLE_NUM_INTS(numFds);
void setFd(int p_fd) {
if (p_fd >= 0) {
- numFds = 1;
- }
- else {
- numFds = 0;
+ numFds++;
}
fd = p_fd;
numInts = CB_HANDLE_NUM_INTS(numFds);
}
+ void setDmaFd(int fd) {
+ if (fd >= 0) {
+ numFds++;
+ }
+ dmafd = fd;
+ numInts = CB_HANDLE_NUM_INTS(numFds);
+ }
+
static bool validate(const cb_handle_t* hnd) {
return (hnd &&
hnd->version == sizeof(native_handle) &&
// file-descriptors
int fd; // ashmem fd (-1 of ashmem region did not allocated, i.e. no SW access needed)
+ int dmafd; // goldfish dma fd.
// ints
int magic; // magic number in order to validate a pointer to be a cb_handle_t
int lockedWidth;
int lockedHeight;
uint32_t hostHandle;
+
+ goldfish_dma_context goldfish_dma;
+ uint32_t goldfish_dma_buf_size;
+ EmulatorFrameworkFormat emuFrameworkFormat;
};
--- /dev/null
+/*
+* 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.
+*/
+#if PLATFORM_SDK_VERSION > 24
+#include <system/qemu_pipe.h>
+#else // PLATFORM_SDK_VERSION
+#include <hardware/qemu_pipe.h>
+#endif //PLATFORM_SDK_VERSION
return EGL_FALSE;
}
- rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(),
- pixelFormat);
+ rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), pixelFormat);
if (!rcColorBuffer) {
ALOGE("rcCreateColorBuffer returned 0");
return EGL_FALSE;
#include <dlfcn.h>
#include <sys/mman.h>
#include "gralloc_cb.h"
+#include "goldfish_dma.h"
+#include "FormatConversions.h"
#include "HostConnection.h"
#include "ProcessPipe.h"
#include "glUtils.h"
void *addr = mmap(0, cb->ashmemSize, PROT_READ | PROT_WRITE,
MAP_SHARED, cb->fd, 0);
if (addr == MAP_FAILED) {
+ ALOGE("%s: failed to map ashmem region!", __FUNCTION__);
return -errno;
}
#define DEFINE_HOST_CONNECTION \
HostConnection *hostCon = HostConnection::get(); \
- renderControl_encoder_context_t *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL)
-
-#define EXIT_GRALLOCONLY_HOST_CONNECTION \
- HostConnection *hostCon = HostConnection::get(); \
- if (hostCon && hostCon->isGrallocOnly()) { \
- ALOGD("%s: exiting HostConnection (is buffer-handling thread)", \
- __FUNCTION__); \
- HostConnection::exit(); \
- }
+ ExtendedRCEncoderContext *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL)
#define DEFINE_AND_VALIDATE_HOST_CONNECTION \
HostConnection *hostCon = HostConnection::get(); \
ALOGE("gralloc: Failed to get host connection\n"); \
return -EIO; \
} \
- renderControl_encoder_context_t *rcEnc = hostCon->rcEncoder(); \
+ ExtendedRCEncoderContext *rcEnc = hostCon->rcEncoder(); \
if (!rcEnc) { \
ALOGE("gralloc: Failed to get renderControl encoder context\n"); \
return -EIO; \
#define HAL_PIXEL_FORMAT_YCbCr_420_888 0xFFFFFFFF
#endif
+static void updateHostColorBuffer(cb_handle_t* cb,
+ bool doLocked,
+ char* pixels) {
+ D("%s: call. doLocked=%d", __FUNCTION__, doLocked);
+ DEFINE_HOST_CONNECTION;
+ int bpp = glUtilsPixelBitSize(cb->glFormat, cb->glType) >> 3;
+ int left = doLocked ? cb->lockedLeft : 0;
+ int top = doLocked ? cb->lockedTop : 0;
+ int width = doLocked ? cb->lockedWidth : cb->width;
+ int height = doLocked ? cb->lockedHeight : cb->height;
+
+ char* to_send = pixels;
+ uint32_t rgbSz = width * height * bpp;
+ uint32_t send_buffer_size = rgbSz;
+ bool is_rgb_format =
+ cb->frameworkFormat != HAL_PIXEL_FORMAT_YV12 &&
+ cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888;
+
+ char* convertedBuf = NULL;
+ if ((doLocked && is_rgb_format) ||
+ (cb->goldfish_dma.fd < 0 &&
+ (doLocked || !is_rgb_format))) {
+ convertedBuf = new char[rgbSz];
+ to_send = convertedBuf;
+ send_buffer_size = rgbSz;
+ }
+
+ if (doLocked && is_rgb_format) {
+ copy_rgb_buffer(to_send, pixels, width, height, top, left, bpp);
+ }
+
+ if (cb->goldfish_dma.fd > 0) {
+ if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
+ get_yv12_offsets(width, height, NULL, NULL,
+ &send_buffer_size);
+ }
+ if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ get_yuv420p_offsets(width, height, NULL, NULL,
+ &send_buffer_size);
+ }
+
+ rcEnc->bindDmaContext(&cb->goldfish_dma);
+ D("%s: call. dma update with sz=%u", __FUNCTION__, send_buffer_size);
+ rcEnc->rcUpdateColorBufferDMA(rcEnc, cb->hostHandle,
+ left, top, width, height,
+ cb->glFormat, cb->glType,
+ to_send, send_buffer_size);
+ } else {
+ if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
+ yv12_to_rgb888(to_send, pixels,
+ width, height, left, top,
+ left + width - 1, top + height - 1);
+ }
+ if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ yuv420p_to_rgb888(to_send, pixels,
+ width, height, left, top,
+ left + width - 1, top + height - 1);
+ }
+ rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle,
+ left, top, width, height,
+ cb->glFormat, cb->glType, to_send);
+ }
+
+ if (convertedBuf) delete [] convertedBuf;
+}
+
//
// gralloc device functions (alloc interface)
//
GLenum glFormat = 0;
GLenum glType = 0;
+ EmulatorFrameworkFormat selectedEmuFrameworkFormat = FRAMEWORK_FORMAT_GL_COMPATIBLE;
int bpp = 0;
int align = 1;
// We are going to use RGB888 on the host
glFormat = GL_RGB;
glType = GL_UNSIGNED_BYTE;
+ selectedEmuFrameworkFormat = FRAMEWORK_FORMAT_YV12;
break;
case HAL_PIXEL_FORMAT_YCbCr_420_888:
ALOGD("%s: 420_888 format experimental path. "
// We are going to use RGB888 on the host
glFormat = GL_RGB;
glType = GL_UNSIGNED_BYTE;
+ selectedEmuFrameworkFormat = FRAMEWORK_FORMAT_YUV_420_888;
break;
default:
ALOGE("gralloc_alloc: Unknown format %d", format);
// round to page size;
ashmem_size = (ashmem_size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
+ ALOGD("%s: Creating ashmem region of size %lu\n", __FUNCTION__, ashmem_size);
fd = ashmem_create_region("gralloc-buffer", ashmem_size);
if (fd < 0) {
ALOGE("gralloc_alloc failed to create ashmem region: %s\n",
cb_handle_t *cb = new cb_handle_t(fd, ashmem_size, usage,
w, h, frameworkFormat, format,
- glFormat, glType);
+ glFormat, glType, selectedEmuFrameworkFormat);
+ DEFINE_HOST_CONNECTION;
if (ashmem_size > 0) {
+
//
// map ashmem region if exist
//
}
cb->setFd(fd);
+
+ if (rcEnc->getDmaVersion() > 0) {
+ D("%s: creating goldfish dma region of size %lu (cb fd %d)\n", __FUNCTION__, ashmem_size, cb->fd);
+ err = goldfish_dma_create_region(ashmem_size, &cb->goldfish_dma);
+ if (err) {
+ ALOGE("%s: Failed to create goldfish DMA region", __FUNCTION__);
+ } else {
+ goldfish_dma_map(&cb->goldfish_dma);
+ cb->setDmaFd(cb->goldfish_dma.fd);
+ D("%s: done, cbfd %d dmafd1 %d dmafd2 %d", __FUNCTION__, cb->fd, cb->goldfish_dma.fd, cb->dmafd);
+ }
+ } else {
+ cb->goldfish_dma.fd = -1;
+ }
+ } else {
+ cb->goldfish_dma.fd = -1;
}
//
GRALLOC_USAGE_HW_2D |
GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_MASK) ) {
#endif // PLATFORM_SDK_VERSION
- ALOGD("%s: format %d and usage 0x%x imply creation of host color buffer",
- __FUNCTION__, frameworkFormat, usage);
- DEFINE_HOST_CONNECTION;
if (hostCon && rcEnc) {
- cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, glFormat);
+ if (cb->goldfish_dma.fd > 0) {
+ cb->hostHandle = rcEnc->rcCreateColorBufferDMA(rcEnc, w, h, glFormat, cb->emuFrameworkFormat);
+ } else {
+ cb->hostHandle = rcEnc->rcCreateColorBuffer(rcEnc, w, h, glFormat);
+ }
D("Created host ColorBuffer 0x%x\n", cb->hostHandle);
}
static int gralloc_free(alloc_device_t* dev,
buffer_handle_t handle)
{
- const cb_handle_t *cb = (const cb_handle_t *)handle;
+ D("%s: start", __FUNCTION__);
+ cb_handle_t *cb = (cb_handle_t *)handle;
if (!cb_handle_t::validate((cb_handle_t*)cb)) {
ERR("gralloc_free: invalid handle");
return -EINVAL;
}
close(cb->fd);
}
+ if (cb->dmafd > 0) {
+ D("%s: unmap and free dma fd %d\n", __FUNCTION__, cb->dmafd);
+ cb->goldfish_dma.fd = cb->dmafd;
+ if (cb->ashmemSize > 0 && cb->ashmemBase) {
+ goldfish_dma_unmap(&cb->goldfish_dma);
+ }
+ goldfish_dma_free(&cb->goldfish_dma);
+ D("%s: closed dma fd %d\n", __FUNCTION__, cb->dmafd);
+ }
+ D("%s: done", __FUNCTION__);
// remove it from the allocated list
gralloc_device_t *grdev = (gralloc_device_t *)dev;
pthread_mutex_lock(&grdev->lock);
delete cb;
+ D("%s: exit", __FUNCTION__);
return 0;
}
static int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
+ D("%s: start", __FUNCTION__);
pthread_once(&sFallbackOnce, fallback_init);
if (sFallback != NULL) {
return sFallback->registerBuffer(sFallback, handle);
return -err;
}
cb->mappedPid = getpid();
+ D("%s: checking to map goldfish dma", __FUNCTION__);
+ if (cb->dmafd > 0) {
+ D("%s: attempting to goldfish dma mmap. cbfd %d dmafd1 %d dmafd2 %d", __FUNCTION__, cb->fd, cb->goldfish_dma.fd, cb->dmafd);
+ D("cxt=%p curr pid %d mapped pid %d",
+ &cb->goldfish_dma,
+ (int)getpid(),
+ cb->mappedPid);
+ if (cb->goldfish_dma.fd != cb->dmafd) {
+ cb->goldfish_dma.fd = cb->dmafd;
+ }
+ goldfish_dma_map(&cb->goldfish_dma);
+ }
}
return 0;
static int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle)
{
+ D("%s: call", __FUNCTION__);
if (sFallback != NULL) {
return sFallback->unregisterBuffer(sFallback, handle);
}
// (through register_buffer)
//
if (cb->ashmemSize > 0 && cb->mappedPid == getpid()) {
+ DEFINE_AND_VALIDATE_HOST_CONNECTION;
void *vaddr;
int err = munmap((void *)cb->ashmemBase, cb->ashmemSize);
if (err) {
}
cb->ashmemBase = 0;
cb->mappedPid = 0;
+ D("%s: Unregister buffer previous mapped to pid %d", __FUNCTION__, getpid());
+ if (cb->dmafd > 0) {
+ cb->goldfish_dma.fd = cb->dmafd;
+ D("%s: Unmap dma fd %d (%d)", __FUNCTION__, cb->dmafd, cb->goldfish_dma.fd);
+ goldfish_dma_unmap(&cb->goldfish_dma);
+ }
}
- D("gralloc_unregister_buffer(%p) done\n", cb);
- EXIT_GRALLOCONLY_HOST_CONNECTION;
+ D("gralloc_unregister_buffer(%p) done\n", cb);
return 0;
}
-static signed clamp_rgb(signed value) {
- if (value > 255) {
- value = 255;
- } else if (value < 0) {
- value = 0;
- }
- return value;
-}
-static void rgb565_to_yv12(char* dest, char* src, int width, int height,
- int left, int top, int right, int bottom) {
- int align = 16;
- int yStride = (width + (align -1)) & ~(align-1);
- int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
- int yOffset = 0;
- int cSize = cStride * height/2;
-
- uint16_t *rgb_ptr0 = (uint16_t *)src;
- uint8_t *yv12_y0 = (uint8_t *)dest;
- uint8_t *yv12_v0 = yv12_y0 + yStride * height;
- uint8_t *yv12_u0 = yv12_v0 + cSize;
-
- for (int j = top; j <= bottom; ++j) {
- uint8_t *yv12_y = yv12_y0 + j * yStride;
- uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
- uint8_t *yv12_u = yv12_v + cSize;
- uint16_t *rgb_ptr = rgb_ptr0 + j * width;
- bool jeven = (j & 1) == 0;
- for (int i = left; i <= right; ++i) {
- uint8_t r = ((rgb_ptr[i]) >> 11) & 0x01f;
- uint8_t g = ((rgb_ptr[i]) >> 5) & 0x03f;
- uint8_t b = (rgb_ptr[i]) & 0x01f;
- // convert to 8bits
- // http://stackoverflow.com/questions/2442576/how-does-one-convert-16-bit-rgb565-to-24-bit-rgb888
- uint8_t R = (r * 527 + 23) >> 6;
- uint8_t G = (g * 259 + 33) >> 6;
- uint8_t B = (b * 527 + 23) >> 6;
- // convert to YV12
- // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
- yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
- bool ieven = (i & 1) == 0;
- if (jeven && ieven) {
- yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
- yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
- }
- }
- }
-}
-
-static void rgb888_to_yv12(char* dest, char* src, int width, int height,
- int left, int top, int right, int bottom) {
- DD("%s convert %d by %d", __func__, width, height);
- int align = 16;
- int yStride = (width + (align -1)) & ~(align-1);
- int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
- int yOffset = 0;
- int cSize = cStride * height/2;
- int rgb_stride = 3;
-
- uint8_t *rgb_ptr0 = (uint8_t *)src;
- uint8_t *yv12_y0 = (uint8_t *)dest;
- uint8_t *yv12_v0 = yv12_y0 + yStride * height;
- uint8_t *yv12_u0 = yv12_v0 + cSize;
-
- for (int j = top; j <= bottom; ++j) {
- uint8_t *yv12_y = yv12_y0 + j * yStride;
- uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
- uint8_t *yv12_u = yv12_v + cSize;
- uint8_t *rgb_ptr = rgb_ptr0 + j * width*rgb_stride;
- bool jeven = (j & 1) == 0;
- for (int i = left; i <= right; ++i) {
- uint8_t R = rgb_ptr[i*rgb_stride];
- uint8_t G = rgb_ptr[i*rgb_stride+1];
- uint8_t B = rgb_ptr[i*rgb_stride+2];
- // convert to YV12
- // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
- yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
- bool ieven = (i & 1) == 0;
- if (jeven && ieven) {
- yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
- yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
- }
- }
- }
-}
-
-static void rgb888_to_yuv420p(char* dest, char* src, int width, int height,
- int left, int top, int right, int bottom) {
- DD("%s convert %d by %d", __func__, width, height);
- int yStride = width;
- int cStride = yStride / 2;
- int yOffset = 0;
- int cSize = cStride * height/2;
- int rgb_stride = 3;
-
- uint8_t *rgb_ptr0 = (uint8_t *)src;
- uint8_t *yv12_y0 = (uint8_t *)dest;
- uint8_t *yv12_u0 = yv12_y0 + yStride * height;
- uint8_t *yv12_v0 = yv12_u0 + cSize;
-
- for (int j = top; j <= bottom; ++j) {
- uint8_t *yv12_y = yv12_y0 + j * yStride;
- uint8_t *yv12_u = yv12_u0 + (j/2) * cStride;
- uint8_t *yv12_v = yv12_u + cStride;
- uint8_t *rgb_ptr = rgb_ptr0 + j * width*rgb_stride;
- bool jeven = (j & 1) == 0;
- for (int i = left; i <= right; ++i) {
- uint8_t R = rgb_ptr[i*rgb_stride];
- uint8_t G = rgb_ptr[i*rgb_stride+1];
- uint8_t B = rgb_ptr[i*rgb_stride+2];
- // convert to YV12
- // frameworks/base/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
- yv12_y[i] = clamp_rgb((77 * R + 150 * G + 29 * B) >> 8);
- bool ieven = (i & 1) == 0;
- if (jeven && ieven) {
- yv12_u[i] = clamp_rgb((( -43 * R - 85 * G + 128 * B) >> 8) + 128);
- yv12_v[i] = clamp_rgb((( 128 * R - 107 * G - 21 * B) >> 8) + 128);
- }
- }
- }
-}
static int gralloc_lock(gralloc_module_t const* module,
buffer_handle_t handle, int usage,
return 0;
}
-// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
-// certain stride requirements for Y and UV respectively.
-static void yv12_to_rgb565(char* dest, char* src, int width, int height,
- int left, int top, int right, int bottom) {
- DD("%s convert %d by %d", __func__, width, height);
- int align = 16;
- int yStride = (width + (align -1)) & ~(align-1);
- int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
- int yOffset = 0;
- int cSize = cStride * height/2;
-
- uint16_t *rgb_ptr0 = (uint16_t *)dest;
- uint8_t *yv12_y0 = (uint8_t *)src;
- uint8_t *yv12_v0 = yv12_y0 + yStride * height;
- uint8_t *yv12_u0 = yv12_v0 + cSize;
-
- for (int j = top; j <= bottom; ++j) {
- uint8_t *yv12_y = yv12_y0 + j * yStride;
- uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
- uint8_t *yv12_u = yv12_v + cSize;
- uint16_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1);
- for (int i = left; i <= right; ++i) {
- // convert to rgb
- // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
- signed y1 = (signed)yv12_y[i] - 16;
- signed u = (signed)yv12_u[i / 2] - 128;
- signed v = (signed)yv12_v[i / 2] - 128;
-
- signed u_b = u * 517;
- signed u_g = -u * 100;
- signed v_g = -v * 208;
- signed v_r = v * 409;
-
- signed tmp1 = y1 * 298;
- signed b1 = clamp_rgb((tmp1 + u_b) / 256);
- signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
- signed r1 = clamp_rgb((tmp1 + v_r) / 256);
-
- uint16_t rgb1 = ((r1 >> 3) << 11) | ((g1 >> 2) << 5) | (b1 >> 3);
-
- rgb_ptr[i-left] = rgb1;
- }
- }
-}
-
-// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
-// certain stride requirements for Y and UV respectively.
-static void yv12_to_rgb888(char* dest, char* src, int width, int height,
- int left, int top, int right, int bottom) {
- DD("%s convert %d by %d", __func__, width, height);
- int align = 16;
- int yStride = (width + (align -1)) & ~(align-1);
- int cStride = (yStride / 2 + (align - 1)) & ~(align-1);
- int yOffset = 0;
- int cSize = cStride * height/2;
- int rgb_stride = 3;
-
- uint8_t *rgb_ptr0 = (uint8_t *)dest;
- uint8_t *yv12_y0 = (uint8_t *)src;
- uint8_t *yv12_v0 = yv12_y0 + yStride * height;
- uint8_t *yv12_u0 = yv12_v0 + cSize;
-
- for (int j = top; j <= bottom; ++j) {
- uint8_t *yv12_y = yv12_y0 + j * yStride;
- uint8_t *yv12_v = yv12_v0 + (j/2) * cStride;
- uint8_t *yv12_u = yv12_v + cSize;
- uint8_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1) * rgb_stride;
- for (int i = left; i <= right; ++i) {
- // convert to rgb
- // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
- signed y1 = (signed)yv12_y[i] - 16;
- signed u = (signed)yv12_u[i / 2] - 128;
- signed v = (signed)yv12_v[i / 2] - 128;
-
- signed u_b = u * 517;
- signed u_g = -u * 100;
- signed v_g = -v * 208;
- signed v_r = v * 409;
-
- signed tmp1 = y1 * 298;
- signed b1 = clamp_rgb((tmp1 + u_b) / 256);
- signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
- signed r1 = clamp_rgb((tmp1 + v_r) / 256);
-
- rgb_ptr[(i-left)*rgb_stride] = r1;
- rgb_ptr[(i-left)*rgb_stride+1] = g1;
- rgb_ptr[(i-left)*rgb_stride+2] = b1;
- }
- }
-}
-
-// YV12 is aka YUV420Planar, or YUV420p; the only difference is that YV12 has
-// certain stride requirements for Y and UV respectively.
-static void yuv420p_to_rgb888(char* dest, char* src, int width, int height,
- int left, int top, int right, int bottom) {
- DD("%s convert %d by %d", __func__, width, height);
- int yStride = width;
- int cStride = yStride / 2;
- int yOffset = 0;
- int cSize = cStride * height/2;
- int rgb_stride = 3;
-
- uint8_t *rgb_ptr0 = (uint8_t *)dest;
- uint8_t *yv12_y0 = (uint8_t *)src;
- uint8_t *yv12_u0 = yv12_y0 + yStride * height;
- uint8_t *yv12_v0 = yv12_u0 + cSize;
-
- for (int j = top; j <= bottom; ++j) {
- uint8_t *yv12_y = yv12_y0 + j * yStride;
- uint8_t *yv12_u = yv12_u0 + (j/2) * cStride;
- uint8_t *yv12_v = yv12_u + cSize;
- uint8_t *rgb_ptr = rgb_ptr0 + (j-top) * (right-left+1) * rgb_stride;
- for (int i = left; i <= right; ++i) {
- // convert to rgb
- // frameworks/av/media/libstagefright/colorconversion/ColorConverter.cpp
- signed y1 = (signed)yv12_y[i] - 16;
- signed u = (signed)yv12_u[i / 2] - 128;
- signed v = (signed)yv12_v[i / 2] - 128;
-
- signed u_b = u * 517;
- signed u_g = -u * 100;
- signed v_g = -v * 208;
- signed v_r = v * 409;
-
- signed tmp1 = y1 * 298;
- signed b1 = clamp_rgb((tmp1 + u_b) / 256);
- signed g1 = clamp_rgb((tmp1 + v_g + u_g) / 256);
- signed r1 = clamp_rgb((tmp1 + v_r) / 256);
-
- rgb_ptr[(i-left)*rgb_stride] = r1;
- rgb_ptr[(i-left)*rgb_stride+1] = g1;
- rgb_ptr[(i-left)*rgb_stride+2] = b1;
- }
- }
-}
-
static int gralloc_unlock(gralloc_module_t const* module,
buffer_handle_t handle)
{
char* rgb_addr = (char *)cpu_addr;
if (cb->lockedWidth < cb->width || cb->lockedHeight < cb->height) {
- int bpp = glUtilsPixelBitSize(cb->glFormat, cb->glType) >> 3;
- char *tmpBuf = new char[cb->lockedWidth * cb->lockedHeight * bpp];
- if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
- yv12_to_rgb888(tmpBuf, (char*)cpu_addr, cb->width, cb->height, cb->lockedLeft,
- cb->lockedTop, cb->lockedLeft+cb->lockedWidth-1, cb->lockedTop+cb->lockedHeight-1);
- } else if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
- yuv420p_to_rgb888(tmpBuf, (char*)cpu_addr, cb->width, cb->height, cb->lockedLeft,
- cb->lockedTop, cb->lockedLeft+cb->lockedWidth-1, cb->lockedTop+cb->lockedHeight-1);
- } else {
- int dst_line_len = cb->lockedWidth * bpp;
- int src_line_len = cb->width * bpp;
- char *src = (char *)rgb_addr + cb->lockedTop*src_line_len + cb->lockedLeft*bpp;
- char *dst = tmpBuf;
- for (int y=0; y<cb->lockedHeight; y++) {
- memcpy(dst, src, dst_line_len);
- src += src_line_len;
- dst += dst_line_len;
- }
- }
-
- rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle,
- cb->lockedLeft, cb->lockedTop,
- cb->lockedWidth, cb->lockedHeight,
- cb->glFormat, cb->glType,
- tmpBuf);
-
- delete [] tmpBuf;
+ updateHostColorBuffer(cb, true, rgb_addr);
}
else {
- char* rgbBuf = 0;
- if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YV12) {
- // for this format, we need to convert to RGB888 format
- // before updating host
- rgbBuf = new char[cb->width * cb->height * 3];
- yv12_to_rgb888(rgbBuf, (char*)cpu_addr, cb->width, cb->height, 0, 0, cb->width-1, cb->height-1);
- rgb_addr = rgbBuf;
- } else if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
- // for this format, we need to convert to RGB888 format
- // before updating host
- rgbBuf = new char[cb->width * cb->height * 3];
- yuv420p_to_rgb888(rgbBuf, (char*)cpu_addr, cb->width, cb->height, 0, 0, cb->width-1, cb->height-1);
- rgb_addr = rgbBuf;
- }
-
- rcEnc->rcUpdateColorBuffer(rcEnc, cb->hostHandle, 0, 0,
- cb->width, cb->height,
- cb->glFormat, cb->glType,
- rgb_addr);
- if (rgbBuf) {
- delete [] rgbBuf;
- }
+ updateHostColorBuffer(cb, false, rgb_addr);
}
DD("gralloc_unlock success. cpu_addr: %p", cpu_addr);
rcFlushWindowColorBufferAsync = (rcFlushWindowColorBufferAsync_client_proc_t) getProc("rcFlushWindowColorBufferAsync", userData);
rcDestroySyncKHR = (rcDestroySyncKHR_client_proc_t) getProc("rcDestroySyncKHR", userData);
rcSetPuid = (rcSetPuid_client_proc_t) getProc("rcSetPuid", userData);
+ rcUpdateColorBufferDMA = (rcUpdateColorBufferDMA_client_proc_t) getProc("rcUpdateColorBufferDMA", userData);
+ rcCreateColorBufferDMA = (rcCreateColorBufferDMA_client_proc_t) getProc("rcCreateColorBufferDMA", userData);
return 0;
}
rcFlushWindowColorBufferAsync_client_proc_t rcFlushWindowColorBufferAsync;
rcDestroySyncKHR_client_proc_t rcDestroySyncKHR;
rcSetPuid_client_proc_t rcSetPuid;
+ rcUpdateColorBufferDMA_client_proc_t rcUpdateColorBufferDMA;
+ rcCreateColorBufferDMA_client_proc_t rcCreateColorBufferDMA;
virtual ~renderControl_client_context_t() {}
typedef renderControl_client_context_t *CONTEXT_ACCESSOR_TYPE(void);
typedef void (renderControl_APIENTRY *rcFlushWindowColorBufferAsync_client_proc_t) (void * ctx, uint32_t);
typedef int (renderControl_APIENTRY *rcDestroySyncKHR_client_proc_t) (void * ctx, uint64_t);
typedef void (renderControl_APIENTRY *rcSetPuid_client_proc_t) (void * ctx, uint64_t);
+typedef int (renderControl_APIENTRY *rcUpdateColorBufferDMA_client_proc_t) (void * ctx, uint32_t, GLint, GLint, GLint, GLint, GLenum, GLenum, void*, uint32_t);
+typedef uint32_t (renderControl_APIENTRY *rcCreateColorBufferDMA_client_proc_t) (void * ctx, uint32_t, uint32_t, GLenum, int);
#endif
}
+int rcUpdateColorBufferDMA_enc(void *self , uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void* pixels, uint32_t pixels_size)
+{
+
+ renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+ IOStream *stream = ctx->m_stream;
+ ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+ bool useChecksum = checksumCalculator->getVersion() > 0;
+
+ const unsigned int __size_pixels = pixels_size;
+ unsigned char *ptr;
+ unsigned char *buf;
+ const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 8 + 4 + 1*4;
+ const size_t checksumSize = checksumCalculator->checksumByteSize();
+ const size_t totalSize = sizeWithoutChecksum + checksumSize;
+ buf = stream->alloc(totalSize);
+ ptr = buf;
+ int tmp = OP_rcUpdateColorBufferDMA;memcpy(ptr, &tmp, 4); ptr += 4;
+ memcpy(ptr, &totalSize, 4); ptr += 4;
+
+ memcpy(ptr, &colorbuffer, 4); ptr += 4;
+ memcpy(ptr, &x, 4); ptr += 4;
+ memcpy(ptr, &y, 4); ptr += 4;
+ memcpy(ptr, &width, 4); ptr += 4;
+ memcpy(ptr, &height, 4); ptr += 4;
+ memcpy(ptr, &format, 4); ptr += 4;
+ memcpy(ptr, &type, 4); ptr += 4;
+ *(uint64_t *)(ptr) = ctx->lockAndWriteDma(pixels, __size_pixels); ptr += 8;
+ memcpy(ptr, &pixels_size, 4); ptr += 4;
+
+ if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+ if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+ int retval;
+ stream->readback(&retval, 4);
+ if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
+ if (useChecksum) {
+ unsigned char *checksumBufPtr = NULL;
+ unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+ if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+ stream->readback(checksumBufPtr, checksumSize);
+ if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+ ALOGE("rcUpdateColorBufferDMA: GL communication error, please report this issue to b.android.com.\n");
+ abort();
+ }
+ }
+ return retval;
+}
+
+uint32_t rcCreateColorBufferDMA_enc(void *self , uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat)
+{
+
+ renderControl_encoder_context_t *ctx = (renderControl_encoder_context_t *)self;
+ IOStream *stream = ctx->m_stream;
+ ChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;
+ bool useChecksum = checksumCalculator->getVersion() > 0;
+
+ unsigned char *ptr;
+ unsigned char *buf;
+ const size_t sizeWithoutChecksum = 8 + 4 + 4 + 4 + 4;
+ const size_t checksumSize = checksumCalculator->checksumByteSize();
+ const size_t totalSize = sizeWithoutChecksum + checksumSize;
+ buf = stream->alloc(totalSize);
+ ptr = buf;
+ int tmp = OP_rcCreateColorBufferDMA;memcpy(ptr, &tmp, 4); ptr += 4;
+ memcpy(ptr, &totalSize, 4); ptr += 4;
+
+ memcpy(ptr, &width, 4); ptr += 4;
+ memcpy(ptr, &height, 4); ptr += 4;
+ memcpy(ptr, &internalFormat, 4); ptr += 4;
+ memcpy(ptr, &frameworkFormat, 4); ptr += 4;
+
+ if (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);
+ if (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;
+
+
+ uint32_t retval;
+ stream->readback(&retval, 4);
+ if (useChecksum) checksumCalculator->addBuffer(&retval, 4);
+ if (useChecksum) {
+ unsigned char *checksumBufPtr = NULL;
+ unsigned char checksumBuf[ChecksumCalculator::kMaxChecksumSize];
+ if (checksumSize > 0) checksumBufPtr = &checksumBuf[0];
+ stream->readback(checksumBufPtr, checksumSize);
+ if (!checksumCalculator->validate(checksumBufPtr, checksumSize)) {
+ ALOGE("rcCreateColorBufferDMA: GL communication error, please report this issue to b.android.com.\n");
+ abort();
+ }
+ }
+ return retval;
+}
+
} // namespace
renderControl_encoder_context_t::renderControl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator)
this->rcFlushWindowColorBufferAsync = &rcFlushWindowColorBufferAsync_enc;
this->rcDestroySyncKHR = &rcDestroySyncKHR_enc;
this->rcSetPuid = &rcSetPuid_enc;
+ this->rcUpdateColorBufferDMA = &rcUpdateColorBufferDMA_enc;
+ this->rcCreateColorBufferDMA = &rcCreateColorBufferDMA_enc;
}
ChecksumCalculator *m_checksumCalculator;
renderControl_encoder_context_t(IOStream *stream, ChecksumCalculator *checksumCalculator);
+ virtual uint64_t lockAndWriteDma(void* data, uint32_t sz) { return 0; }
};
#endif // GUARD_renderControl_encoder_context_t
\ No newline at end of file
void rcFlushWindowColorBufferAsync(uint32_t windowSurface);
int rcDestroySyncKHR(uint64_t sync);
void rcSetPuid(uint64_t puid);
+ int rcUpdateColorBufferDMA(uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void* pixels, uint32_t pixels_size);
+ uint32_t rcCreateColorBufferDMA(uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat);
};
#endif
ctx->rcSetPuid(ctx, puid);
}
+int rcUpdateColorBufferDMA(uint32_t colorbuffer, GLint x, GLint y, GLint width, GLint height, GLenum format, GLenum type, void* pixels, uint32_t pixels_size)
+{
+ GET_CONTEXT;
+ return ctx->rcUpdateColorBufferDMA(ctx, colorbuffer, x, y, width, height, format, type, pixels, pixels_size);
+}
+
+uint32_t rcCreateColorBufferDMA(uint32_t width, uint32_t height, GLenum internalFormat, int frameworkFormat)
+{
+ GET_CONTEXT;
+ return ctx->rcCreateColorBufferDMA(ctx, width, height, internalFormat, frameworkFormat);
+}
+
{"rcFlushWindowColorBufferAsync", (void*)rcFlushWindowColorBufferAsync},
{"rcDestroySyncKHR", (void*)rcDestroySyncKHR},
{"rcSetPuid", (void*)rcSetPuid},
+ {"rcUpdateColorBufferDMA", (void*)rcUpdateColorBufferDMA},
+ {"rcCreateColorBufferDMA", (void*)rcCreateColorBufferDMA},
};
static const int renderControl_num_funcs = sizeof(renderControl_funcs_by_name) / sizeof(struct _renderControl_funcs_by_name);
#define OP_rcFlushWindowColorBufferAsync 10031
#define OP_rcDestroySyncKHR 10032
#define OP_rcSetPuid 10033
-#define OP_last 10034
+#define OP_rcUpdateColorBufferDMA 10034
+#define OP_rcCreateColorBufferDMA 10035
+#define OP_last 10036
#endif