blob: 3acdd7d5c9647f81add8e9bcc3504397337c64b5 [file] [log] [blame]
/*
* Copyright (C) 2008 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 "graphics_translation/gralloc/graphics_buffer.h"
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <GLES2/gl2.h>
#include "common/alog.h"
#include "common/shared_object_tracker.h"
#include "graphics_translation/egl/color_buffer.h"
#include "graphics_translation/egl/egl_display_impl.h"
#include "graphics_translation/gralloc/gralloc.h"
#include "hardware/gralloc.h"
static ColorBufferPtr GetColorBuffer(void* hnd) {
EglDisplayImpl* display = EglDisplayImpl::GetDefaultDisplay();
return display->GetColorBuffers().Get(hnd);
}
static int GetBytesPerPixel(GLenum format, GLenum type) {
if (type == GL_BYTE || type == GL_UNSIGNED_BYTE) {
switch (format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL_OES:
return 1;
case GL_LUMINANCE_ALPHA:
return 2;
case GL_RGB:
return 3;
case GL_RGBA:
case GL_BGRA_EXT:
return 4;
default:
LOG_ALWAYS_FATAL("Unknown format: %d", format);
}
}
switch (type) {
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:
return 2;
case GL_INT:
case GL_UNSIGNED_INT:
case GL_FLOAT:
case GL_FIXED:
case GL_UNSIGNED_INT_24_8_OES:
return 4;
default:
LOG_ALWAYS_FATAL("Unknown type: %d", type);
}
return 0;
}
GraphicsBuffer::GraphicsBuffer(size_t size, int usage, int width, int height,
int format, int gl_format, int gl_type)
: fd_(-1),
magic_(kMagicValue),
usage_(usage),
width_(width),
height_(height),
format_(format),
gl_format_(gl_format),
gl_type_(gl_type),
locked_left_(0),
locked_top_(0),
locked_width_(0),
locked_height_(0),
system_texture_(0),
system_target_(0),
system_texture_tracking_handle_(0),
sw_buffer_size_(size),
sw_buffer_(NULL),
hw_handle_(NULL),
locked_addr_(NULL) {
const int hw_flags =
(GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_2D | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB);
const int sw_write_flags =
(GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_CAMERA_WRITE);
if (usage_ & hw_flags) {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
hw_handle_ = ColorBuffer::Create(display, width_, height_, gl_format_,
gl_type_, usage_ & sw_write_flags);
LOG_ALWAYS_FATAL_IF(!hw_handle_, "Failed to create h/w buffer.");
}
// Update the NativeHandle data fields.
version = GetVersion();
numFds = 0;
if (size != 0) {
fd_ = 0;
numFds = 1;
}
numInts = CalculateNumInts(numFds);
}
GraphicsBuffer::~GraphicsBuffer() {
Release();
SetObjectTrackingHandle(0);
delete[] sw_buffer_;
sw_buffer_ = NULL;
// Clear out some of the fields to help ensure we are only ever accessing valid
// GraphicsBuffer objects.
magic_ = 0;
fd_ = -1;
}
int GraphicsBuffer::Acquire() {
if (hw_handle_) {
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (cb) {
cb->Acquire();
} else {
return -EINVAL;
}
}
return 0;
}
int GraphicsBuffer::Release() {
if (hw_handle_) {
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (cb) {
cb->Release();
} else {
return -EINVAL;
}
}
return 0;
}
int GraphicsBuffer::Lock(int usage, int left, int top, int width, int height,
void** vaddr) {
if (locked_addr_) {
ALOGE("Try locking a locked graphics buffer.");
return -EBUSY;
}
const bool sw_read = (usage & GRALLOC_USAGE_SW_READ_MASK);
const bool hw_read = (usage & GRALLOC_USAGE_HW_TEXTURE);
const bool sw_write = (usage & GRALLOC_USAGE_SW_WRITE_MASK);
const bool hw_write = (usage & GRALLOC_USAGE_HW_RENDER);
const bool hw_cam_read = (usage & GRALLOC_USAGE_HW_CAMERA_READ);
const bool hw_cam_write = (usage & GRALLOC_USAGE_HW_CAMERA_WRITE);
const bool hw_vid_enc_read = (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER);
const bool sw_read_allowed = (usage_ & GRALLOC_USAGE_SW_READ_MASK);
const bool sw_write_allowed = (usage_ & GRALLOC_USAGE_SW_WRITE_MASK);
// Validate usage.
// 1. Cannot be locked for h/w access.
// 2. Lock for either s/w read or write.
// 3. Locked s/w access must match usage during alloc time.
if ((hw_read || hw_write) || (sw_read && !sw_read_allowed) ||
(sw_write && !sw_write_allowed) ||
(!sw_read && !sw_write && !hw_cam_write && !hw_cam_read &&
!hw_vid_enc_read)) {
ALOGE("Usage mismatch usage=0x%x usage_=0x%x\n", usage, usage_);
return -EINVAL;
}
const bool request_read = (sw_read || hw_cam_read || hw_vid_enc_read);
const bool request_write = (sw_write || hw_cam_write);
if (left == 0 && top == 0 && width == width_ && height == height_ &&
hw_handle_ && request_write && !sw_read_allowed) {
// Only use cb->Lock() for write only graphics buffers.
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (!cb) {
return -EACCES;
}
locked_addr_ = static_cast<char*>(cb->Lock(0, 0, width_, height_,
gl_format_, gl_type_));
} else if (CanBePosted() || request_read || request_write) {
if (sw_buffer_ == NULL && sw_buffer_size_ > 0) {
sw_buffer_ = new char[sw_buffer_size_];
}
locked_addr_ = sw_buffer_;
}
if (locked_addr_ == NULL) {
return -EACCES;
}
if (sw_write || hw_cam_write) {
locked_left_ = left;
locked_top_ = top;
locked_width_ = width;
locked_height_ = height;
}
if (vaddr) {
*vaddr = locked_addr_;
}
return 0;
}
int GraphicsBuffer::Unlock() {
// If buffer was locked for s/w write, then we need to update it.
if (locked_width_ > 0 && locked_height_ > 0 && hw_handle_) {
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (cb) {
if (locked_addr_ == sw_buffer_) {
const int bpp = GetBytesPerPixel(gl_format_, gl_type_);
const int dst_line_len = locked_width_ * bpp;
const int src_line_len = width_ * bpp;
const char* src = locked_addr_ + (locked_top_ * src_line_len) +
(locked_left_ * bpp);
void* tmp = cb->Lock(locked_left_, locked_top_, locked_width_,
locked_height_, gl_format_, gl_type_);
char* dst = static_cast<char*>(tmp);
for (int y = 0; y < locked_height_; y++) {
memcpy(dst, src, dst_line_len);
src += src_line_len;
dst += dst_line_len;
}
cb->Unlock(tmp);
} else {
cb->Unlock(locked_addr_);
}
}
}
locked_left_ = 0;
locked_top_ = 0;
locked_width_ = 0;
locked_height_ = 0;
locked_addr_ = NULL;
return 0;
}
void GraphicsBuffer::SetSystemTexture(int target, int name) {
ALOG_ASSERT(usage_ & GRALLOC_USAGE_ARC_SYSTEM_TEXTURE);
ALOG_ASSERT(target != 0);
system_target_ = target;
system_texture_ = name;
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (cb) {
EglImagePtr image = cb->GetImage();
image->global_texture_target = target;
image->global_texture_name = name;
}
}
void GraphicsBuffer::ClearSystemTexture() {
SetSystemTexture(GL_TEXTURE_2D, 0);
}
void GraphicsBuffer::SetObjectTrackingHandle(int handle) {
if (system_texture_tracking_handle_) {
arc::SharedObjectTracker::DecRef(system_texture_tracking_handle_);
}
system_texture_tracking_handle_ = handle;
if (system_texture_tracking_handle_) {
arc::SharedObjectTracker::IncRef(system_texture_tracking_handle_);
}
}
int GraphicsBuffer::GetHostTarget() const {
if (usage_ & GRALLOC_USAGE_ARC_SYSTEM_TEXTURE) {
return system_target_;
} else {
return GL_TEXTURE_2D;
}
}
int GraphicsBuffer::GetHostTexture() const {
if (usage_ & GRALLOC_USAGE_ARC_SYSTEM_TEXTURE) {
return system_texture_;
} else {
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (cb) {
return cb->GetGlobalTexture();
} else {
return 0;
}
}
}
void* GraphicsBuffer::GetHostContext() const {
if (usage_ & GRALLOC_USAGE_ARC_SYSTEM_TEXTURE) {
return NULL;
} else {
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (cb) {
return cb->GetHostContext();
} else {
return NULL;
}
}
}
bool GraphicsBuffer::CanBePosted() const {
return (usage_ & GRALLOC_USAGE_HW_FB);
}
int GraphicsBuffer::Post() {
if (!CanBePosted()) {
return -EINVAL;
}
ColorBufferPtr cb = GetColorBuffer(hw_handle_);
if (cb) {
cb->Render();
}
glFlush();
return 0;
}
bool GraphicsBuffer::IsValid() const {
return magic_ == kMagicValue && version == GetVersion() &&
numInts == CalculateNumInts(numFds);
}
int GraphicsBuffer::GetVersion() {
return sizeof(native_handle);
}
int GraphicsBuffer::CalculateNumInts(int numFds) {
// The native_handle structure uses these sizes to figure out where all
// the data for this class is exactly.
const size_t self = sizeof(GraphicsBuffer); // NOLINT(runtime/sizeof)
const size_t size = self - (numFds * sizeof(int)); // NOLINT(runtime/sizeof)
return static_cast<int>(size / sizeof(int)); // NOLINT(runtime/sizeof)
}