| /* |
| * 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) |
| } |