blob: 0605c04f9b0db75fe952f36ab47d168e94a17e55 [file] [log] [blame]
/*
* Copyright (C) 2015 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.
*/
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#define LOG_TAG "GLCompositor"
#include <vector>
#include <cutils/log.h>
#include <ui/GraphicBuffer.h>
#include <utils/Trace.h>
#include <sync/sync.h>
#include <sw_sync.h>
#include "drm_hwcomposer.h"
#include "gl_compositor.h"
#include "glworker.h"
namespace android {
static const char *get_gl_error(void);
static const char *get_egl_error(void);
static bool has_extension(const char *extension, const char *extensions);
template <typename T>
int AllocResource(std::vector<T> &array) {
for (typename std::vector<T>::iterator it = array.begin(); it != array.end();
++it) {
if (!it->is_some()) {
return std::distance(array.begin(), it);
}
}
array.push_back(T());
return array.size() - 1;
}
template <typename T>
void FreeResource(std::vector<T> &array, int index) {
if (index == (int)array.size() - 1) {
array.pop_back();
} else if (index >= 0 && (unsigned)index < array.size()) {
array[index].Reset();
}
}
struct GLTarget {
sp<GraphicBuffer> fb;
bool forgotten;
unsigned composition_count;
GLTarget() : forgotten(true), composition_count(0) {
}
void Reset() {
fb.clear();
forgotten = true;
composition_count = 0;
}
bool is_some() const {
return fb != NULL;
}
};
struct GLCompositor::priv_data {
int current_target;
std::vector<GLTarget> targets;
std::vector<GLComposition *> compositions;
GLWorker worker;
priv_data() : current_target(-1) {
}
};
class GLComposition : public Composition {
public:
struct LayerData {
hwc_layer_1 layer;
hwc_drm_bo bo;
};
GLComposition(GLCompositor *owner, Importer *imp)
: compositor(owner), importer(imp), target_handle(-1), timeline_fd(-1) {
int ret = sw_sync_timeline_create();
if (ret < 0) {
ALOGE("Failed to create sw sync timeline %d", ret);
}
timeline_fd = ret;
}
virtual ~GLComposition() {
if (timeline_fd >= 0)
close(timeline_fd);
if (compositor == NULL) {
return;
}
// Removes this composition from the owning compositor automatically.
std::vector<GLComposition *> &compositions =
compositor->priv_->compositions;
std::vector<GLComposition *>::iterator it =
std::find(compositions.begin(), compositions.end(), this);
if (it != compositions.end()) {
compositions.erase(it);
}
GLTarget *target = &compositor->priv_->targets[target_handle];
target->composition_count--;
compositor->CheckAndDestroyTarget(target_handle);
}
virtual int AddLayer(int display, hwc_layer_1 *layer, hwc_drm_bo *bo) {
(void)display;
if (layer->compositionType != HWC_OVERLAY) {
ALOGE("Must add layers with compositionType == HWC_OVERLAY");
return 1;
}
if (layer->handle == 0) {
ALOGE("Must add layers with valid buffer handle");
return 1;
}
layer->releaseFenceFd = sw_sync_fence_create(
timeline_fd, "GLComposition release fence", layers.size() + 1);
layers.push_back(*layer);
return importer->ReleaseBuffer(bo);
}
virtual unsigned GetRemainingLayers(int display, unsigned num_needed) const {
(void)display;
return num_needed;
}
GLCompositor *compositor;
Importer *importer;
int target_handle;
int timeline_fd;
std::vector<hwc_layer_1> layers;
};
GLCompositor::GLCompositor() {
priv_ = new priv_data;
}
GLCompositor::~GLCompositor() {
for (std::vector<GLComposition *>::iterator it = priv_->compositions.end();
it != priv_->compositions.begin(); it = priv_->compositions.end()) {
--it;
// Prevents compositor from trying to erase itself
(*it)->compositor = NULL;
delete *it;
priv_->compositions.erase(it);
}
delete priv_;
}
int GLCompositor::Init() {
return priv_->worker.Init();
}
Targeting *GLCompositor::targeting() {
return (Targeting *)this;
}
int GLCompositor::CreateTarget(sp<GraphicBuffer> &buffer) {
int ret;
int target_handle = AllocResource(priv_->targets);
GLTarget *target = &priv_->targets[target_handle];
target->fb = buffer;
target->forgotten = false;
return target_handle;
}
void GLCompositor::SetTarget(int target_handle) {
if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
GLTarget *target = &priv_->targets[target_handle];
if (target->is_some()) {
priv_->current_target = target_handle;
return;
}
}
priv_->current_target = -1;
}
void GLCompositor::ForgetTarget(int target_handle) {
if (target_handle >= 0 && (unsigned)target_handle < priv_->targets.size()) {
if (target_handle == priv_->current_target) {
priv_->current_target = -1;
}
GLTarget *target = &priv_->targets[target_handle];
if (target->is_some()) {
target->forgotten = true;
CheckAndDestroyTarget(target_handle);
return;
}
}
ALOGE("Failed to forget target because of invalid handle");
}
void GLCompositor::CheckAndDestroyTarget(int target_handle) {
GLTarget *target = &priv_->targets[target_handle];
if (target->composition_count == 0 && target->forgotten) {
FreeResource(priv_->targets, target_handle);
}
}
Composition *GLCompositor::CreateComposition(Importer *importer) {
if (priv_->current_target >= 0 &&
(unsigned)priv_->current_target < priv_->targets.size()) {
GLTarget *target = &priv_->targets[priv_->current_target];
if (target->is_some()) {
GLComposition *composition = new GLComposition(this, importer);
composition->target_handle = priv_->current_target;
target->composition_count++;
priv_->compositions.push_back(composition);
return composition;
}
}
ALOGE("Failed to create composition because of invalid target handle %d",
priv_->current_target);
return NULL;
}
int GLCompositor::QueueComposition(Composition *composition) {
if (composition) {
GLComposition *gl_composition = (GLComposition *)composition;
int ret = DoComposition(gl_composition);
gl_composition->timeline_fd = -1;
delete composition;
return ret;
}
ALOGE("Failed to queue composition because of invalid composition handle");
return -EINVAL;
}
int GLCompositor::Composite() {
return 0;
}
int GLCompositor::DoComposition(GLComposition *composition) {
ATRACE_CALL();
int ret = 0;
GLTarget *target = &priv_->targets[composition->target_handle];
GLWorker::Work work;
work.layers = composition->layers.data();
work.num_layers = composition->layers.size();
work.timeline_fd = composition->timeline_fd;
work.framebuffer = target->fb;
ret = priv_->worker.DoWork(&work);
if (work.timeline_fd >= 0) {
sw_sync_timeline_inc(work.timeline_fd, work.num_layers + 1);
close(work.timeline_fd);
}
return ret;
}
} // namespace android