sdm: Add support for hybrid composition
- Add interface for hybrid composition where some part
of layer is composed by blit engine and rest by SDE.
- Use BlitEngine interface for the blit composition
- Allocate blit target buffers in Commit and use Reconfig to
re-validate the Hybrid composition
- Add C2D as a BlitEngine to get layers composed on the blit
target.
Change-Id: I849da73055920ab13c1a260c9511478457e6894b
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index 37182cc..e5b23cc 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -62,16 +62,32 @@
@sa Layer
*/
enum LayerComposition {
- kCompositionGPU, //!< This layer will be drawn into the target buffer by GPU. Display
- //!< device will mark the layer for SDE composition if it can handle it
- //!< or it will mark the layer for GPU composition.
+ kCompositionGPU, //!< This layer will be drawn onto the target buffer by GPU. Display
+ //!< device will mark the layer for GPU composition if it can not handle
+ //!< it completely.
- kCompositionSDE, //!< This layer will be handled by SDE. It must not be composed by GPU.
+ kCompositionSDE, //!< This layer will be handled by SDE. It must not be composed by GPU.
- kCompositionGPUTarget, //!< This layer will hold result of composition for layers marked for GPU
- //!< composition. If display device sets all other layers for SDE
- //!< composition then this layer would be ignored during Commit().
- //!< Only one layer shall be marked as target buffer by the caller.
+ kCompositionHybrid, //!< This layer will be drawn by a blit engine and SDE together. Display
+ //!< device will split the layer, update the blit rectangle that
+ //!< need to be composed by a blit engine and update original source
+ //!< rectangle that will be composed by SDE.
+
+ kCompositionBlit, //!< This layer will be composed using Blit Engine
+
+ kCompositionGPUTarget, //!< This layer will hold result of composition for layers marked for
+ //!< GPU composition.
+ //!< If display device does not set any layer for SDE composition then
+ //!< this would be ignored during Commit().
+ //!< Only one layer shall be marked as target buffer by the caller.
+ //!< GPU target layer shall be after application layers in layer stack.
+
+ kCompositionBlitTarget, //!< This layer will hold result of composition for blit rectangles
+ //!< from the layers marked for hybrid composition. Nth blit rectangle
+ //!< in a layer shall be composed onto Nth blit target.
+ //!< If display device does not set any layer for hybrid composition
+ //!< then this would be ignored during Commit().
+ //!< Blit target layers shall be after GPU target layer in layer stack.
};
enum LayerColorSpace {
@@ -138,10 +154,15 @@
//!< stack contains secure layers.
uint32_t animating : 1; //!< This flag shall be set by client to indicate that the
- //!< current frame is animating.
- };
+ //!< current frame is animating.i
- uint32_t flags; //!< For initialization purpose only. Client shall not refer it directly.
+ uint64_t attributes_changed : 1;
+ //!< This flag shall be set by client to indicate that the
+ //!< current frame has some properties changed and
+ //!< needs re-config.
+ };
+
+ uint32_t flags; //!< For initialization purpose only. Client shall not refer it directly.
};
LayerStackFlags() : flags(0) { }
@@ -202,6 +223,11 @@
LayerRectArray dirty_regions; //!< Rectangular areas in the current frames that have changed
//!< in comparison to previous frame.
+ LayerRectArray blit_regions; //!< Rectangular areas of this layer which need to composed
+ //!< to blit target. Display device will update blit rectangles
+ //!< if a layer composition is set as hybrid. Nth blit rectangle
+ //!< shall be composed onto Nth blit target.
+
LayerBlending blending; //!< Blending operation which need to be applied on the layer
//!< buffer during composition.
diff --git a/sdm/include/utils/constants.h b/sdm/include/utils/constants.h
index bf5a916..9ea6e70 100644
--- a/sdm/include/utils/constants.h
+++ b/sdm/include/utils/constants.h
@@ -87,6 +87,7 @@
const int kThreadPriorityUrgent = -9;
const int kMaxRotatePerLayer = 2;
+ const uint32_t kMaxBlitTargetLayers = 2;
typedef void * Handle;
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 69e3ec7..d20f0b6 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -258,6 +258,29 @@
return kErrorNone;
}
+DisplayError CompManager::ReConfigure(Handle display_ctx, HWLayers *hw_layers) {
+ SCOPE_LOCK(locker_);
+
+ DisplayCompositionContext *display_comp_ctx =
+ reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+ Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
+
+ DisplayError error = kErrorUndefined;
+ resource_intf_->Start(display_resource_ctx);
+ error = resource_intf_->Acquire(display_resource_ctx, hw_layers);
+
+ if (error != kErrorNone) {
+ DLOGE("Reconfigure failed for display = %d", display_comp_ctx->display_type);
+ }
+
+ resource_intf_->Stop(display_resource_ctx);
+ if (error != kErrorNone) {
+ error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers);
+ }
+
+ return error;
+}
+
DisplayError CompManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
SCOPE_LOCK(locker_);
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index f48beed..61e0581 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -49,6 +49,7 @@
void PrePrepare(Handle display_ctx, HWLayers *hw_layers);
DisplayError Prepare(Handle display_ctx, HWLayers *hw_layers);
DisplayError PostPrepare(Handle display_ctx, HWLayers *hw_layers);
+ DisplayError ReConfigure(Handle display_ctx, HWLayers *hw_layers);
DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers);
void Purge(Handle display_ctx);
bool ProcessIdleTimeout(Handle display_ctx);
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 6cda9fd..a751b20 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -214,6 +214,19 @@
pending_commit_ = false;
+ // Layer stack attributes has changed, need to Reconfigure, currently in use for Hybrid Comp
+ if (layer_stack->flags.attributes_changed) {
+ error = comp_manager_->ReConfigure(display_comp_ctx_, &hw_layers_);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ error = hw_intf_->Validate(&hw_layers_);
+ if (error != kErrorNone) {
+ return error;
+ }
+ }
+
if (rotator_intf_ && IsRotationRequired(&hw_layers_)) {
error = rotator_intf_->Commit(display_rotator_ctx_, &hw_layers_);
if (error != kErrorNone) {
@@ -563,7 +576,10 @@
switch (composition) {
case kCompositionGPU: return "GPU";
case kCompositionSDE: return "SDE";
+ case kCompositionHybrid: return "HYBRID";
+ case kCompositionBlit: return "BLIT";
case kCompositionGPUTarget: return "GPU_TARGET";
+ case kCompositionBlitTarget: return "BLIT_TARGET";
default: return "UNKNOWN";
}
}
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index 183384e..f009d3a 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -128,16 +128,17 @@
return kErrorUndefined;
}
- // Mark all layers for GPU composition. Find GPU target buffer and store its index for
+ // Mark all application layers for GPU composition. Find GPU target buffer and store its index for
// programming the hardware.
LayerStack *layer_stack = hw_layers_info_->stack;
uint32_t &hw_layer_count = hw_layers_info_->count;
hw_layer_count = 0;
+
for (uint32_t i = 0; i < layer_stack->layer_count; i++) {
LayerComposition &composition = layer_stack->layers[i].composition;
if (composition == kCompositionGPUTarget) {
hw_layers_info_->index[hw_layer_count++] = i;
- } else {
+ } else if (composition != kCompositionBlitTarget) {
composition = kCompositionGPU;
}
}
diff --git a/sdm/libs/hwc/Android.mk b/sdm/libs/hwc/Android.mk
index ed07ac3..56992d4 100644
--- a/sdm/libs/hwc/Android.mk
+++ b/sdm/libs/hwc/Android.mk
@@ -7,7 +7,9 @@
LOCAL_C_INCLUDES := hardware/qcom/display/sdm/include/ \
hardware/qcom/display/libgralloc/ \
hardware/qcom/display/libqservice/ \
- hardware/qcom/display/libqdutils/
+ hardware/qcom/display/libqdutils/ \
+ hardware/qcom/display/libcopybit/
+
LOCAL_CFLAGS := -Wno-missing-field-initializers -Wno-unused-parameter \
-Wconversion -Wall -Werror \
-DLOG_TAG=\"SDM\"
@@ -19,7 +21,7 @@
LOCAL_SHARED_LIBRARIES := libsdmcore libqservice libbinder libhardware libhardware_legacy \
libutils libcutils libsync libmemalloc libqdutils libdl \
- libpowermanager
+ libpowermanager libsdmutils
LOCAL_SRC_FILES := hwc_session.cpp \
hwc_display.cpp \
@@ -29,6 +31,7 @@
hwc_debugger.cpp \
hwc_buffer_allocator.cpp \
hwc_buffer_sync_handler.cpp \
- hwc_color_manager.cpp
+ hwc_color_manager.cpp \
+ blit_engine_c2d.cpp
include $(BUILD_SHARED_LIBRARY)
diff --git a/sdm/libs/hwc/blit_engine.h b/sdm/libs/hwc/blit_engine.h
new file mode 100644
index 0000000..6fa9733
--- /dev/null
+++ b/sdm/libs/hwc/blit_engine.h
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*! @file blit_engine.h
+ @brief Interface file for Blit based compositior.
+
+ @details The client can use this interface to get the blit composition done
+
+*/
+
+#ifndef __BLIT_ENGINE_H__
+#define __BLIT_ENGINE_H__
+
+namespace sdm {
+
+/*! @brief Blit Engine implemented by the client
+
+ @details This class declares prototype for BlitEngine Interface which must be
+ implemented by the client. HWC will use this interface to use a Blit engine to get the
+ composition done.
+
+*/
+class BlitEngine {
+ public:
+ BlitEngine() { }
+ virtual ~BlitEngine() { }
+
+ virtual int Init() = 0;
+ virtual void DeInit() = 0;
+ virtual int Prepare(LayerStack *layer_stack) = 0;
+ virtual int PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) = 0;
+ virtual int Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) = 0;
+ virtual void PostCommit(LayerStack *layer_stack) = 0;
+ virtual bool BlitActive() = 0;
+ virtual void SetFrameDumpConfig(uint32_t count) = 0;
+};
+
+} // namespace sdm
+
+#endif // __BLIT_ENGINE_H__
diff --git a/sdm/libs/hwc/blit_engine_c2d.cpp b/sdm/libs/hwc/blit_engine_c2d.cpp
new file mode 100644
index 0000000..0fbe148
--- /dev/null
+++ b/sdm/libs/hwc/blit_engine_c2d.cpp
@@ -0,0 +1,563 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+* Portions formerly licensed under Apache License, Version 2.0, are re licensed
+* under section 4 of Apache License, Version 2.0.
+
+* Copyright (C) 2010 The Android Open Source Project
+
+* Not a Contribution.
+
+* 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 <hardware/hardware.h>
+#include <sync/sync.h>
+#include <copybit.h>
+#include <memalloc.h>
+#include <alloc_controller.h>
+#include <gr.h>
+
+#include <utils/constants.h>
+#include <utils/rect.h>
+
+#include "blit_engine_c2d.h"
+
+#define __CLASS__ "BlitEngineC2D"
+
+namespace sdm {
+
+
+BlitEngineC2d::RegionIterator::RegionIterator(LayerRectArray rect) {
+ rect_array = rect;
+ r.end = INT(rect.count);
+ r.current = 0;
+ this->next = iterate;
+}
+
+int BlitEngineC2d::RegionIterator::iterate(copybit_region_t const *self, copybit_rect_t *rect) {
+ if (!self || !rect) {
+ DLOGE("iterate invalid parameters");
+ return 0;
+ }
+
+ RegionIterator const *me = static_cast<RegionIterator const*>(self);
+ if (me->r.current != me->r.end) {
+ rect->l = INT(me->rect_array.rect[me->r.current].left);
+ rect->t = INT(me->rect_array.rect[me->r.current].top);
+ rect->r = INT(me->rect_array.rect[me->r.current].right);
+ rect->b = INT(me->rect_array.rect[me->r.current].bottom);
+ me->r.current++;
+ return 1;
+ }
+ return 0;
+}
+
+BlitEngineC2d::BlitEngineC2d() : blit_active_(false), dump_frame_count_(0), dump_frame_index_(0) {
+ for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
+ blit_target_buffer_[i] = NULL;
+ release_fence_fd_[i] = -1;
+ }
+}
+
+BlitEngineC2d::~BlitEngineC2d() {
+ if (blit_engine_c2d_) {
+ copybit_close(blit_engine_c2d_);
+ blit_engine_c2d_ = NULL;
+ }
+ FreeBlitTargetBuffers();
+}
+
+int BlitEngineC2d::Init() {
+ hw_module_t const *module;
+
+ if (hw_get_module("copybit", &module) == 0) {
+ if (copybit_open(module, &blit_engine_c2d_) < 0) {
+ DLOGI("CopyBitC2D Open failed.");
+ return -1;
+ }
+ DLOGI("Opened Copybit Module");
+ } else {
+ DLOGI("Copybit HW Module not found");
+ return -1;
+ }
+
+ return 0;
+}
+
+void BlitEngineC2d::DeInit() {
+ FreeBlitTargetBuffers();
+ if (blit_engine_c2d_) {
+ copybit_close(blit_engine_c2d_);
+ blit_engine_c2d_ = NULL;
+ }
+}
+
+int BlitEngineC2d::AllocateBlitTargetBuffers(uint32_t width, uint32_t height, uint32_t format) {
+ int status = 0;
+ if (width <= 0 || height <= 0) {
+ return false;
+ }
+
+ if (blit_target_buffer_[0]) {
+ // Free and reallocate the buffers if the w/h changes
+ if (INT(width) != blit_target_buffer_[0]->width ||
+ INT(height) != blit_target_buffer_[0]->height) {
+ FreeBlitTargetBuffers();
+ }
+ }
+
+ for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
+ if (blit_target_buffer_[i] == NULL) {
+ status = alloc_buffer(&blit_target_buffer_[i], width, height, format,
+ GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
+ }
+ if (status < 0) {
+ DLOGE("Allocation of Blit target Buffer failed");
+ FreeBlitTargetBuffers();
+ break;
+ }
+ }
+
+ return status;
+}
+
+void BlitEngineC2d::FreeBlitTargetBuffers() {
+ for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
+ private_handle_t **target_buffer = &blit_target_buffer_[i];
+ if (*target_buffer) {
+ // Free the valid fence
+ if (release_fence_fd_[i] >= 0) {
+ close(release_fence_fd_[i]);
+ release_fence_fd_[i] = -1;
+ }
+ free_buffer(*target_buffer);
+ *target_buffer = NULL;
+ }
+ }
+}
+
+int BlitEngineC2d::ClearTargetBuffer(private_handle_t* hnd, const LayerRect& rect) {
+ int status = 0;
+ copybit_rect_t clear_rect = {INT(rect.left), INT(rect.top), INT(rect.right), INT(rect.bottom)};
+
+ copybit_image_t buffer;
+ buffer.w = ALIGN((hnd->width), 32);
+ buffer.h = hnd->height;
+ buffer.format = hnd->format;
+ buffer.base = reinterpret_cast<void *>(hnd->base);
+ buffer.handle = reinterpret_cast<native_handle_t *>(hnd);
+
+ status = blit_engine_c2d_->clear(blit_engine_c2d_, &buffer, &clear_rect);
+ return status;
+}
+
+void BlitEngineC2d::PostCommit(LayerStack *layer_stack) {
+ int fence_fd = -1;
+ uint32_t count = 0;
+ int fd = -1;
+
+ for (uint32_t i = blit_target_start_index_-2; (i > 0) && (count < num_blit_target_); i--) {
+ Layer &layer = layer_stack->layers[i];
+ LayerBuffer *layer_buffer = layer.input_buffer;
+ if (layer.composition == kCompositionBlit) {
+ int index = blit_target_start_index_ + count;
+ layer_buffer->release_fence_fd = layer_stack->layers[index].input_buffer->release_fence_fd;
+ fence_fd = layer_buffer->release_fence_fd;
+ close(layer_buffer->acquire_fence_fd);
+ layer_buffer->acquire_fence_fd = -1;
+ layer_stack->layers[index].input_buffer->release_fence_fd = -1;
+ fd = layer_stack->layers[index].input_buffer->acquire_fence_fd;
+ layer_stack->layers[index].input_buffer->acquire_fence_fd = -1;
+ count++;
+ }
+ }
+
+ if (fd >= 0) {
+ // Close the C2D fence FD
+ close(fd);
+ }
+ SetReleaseFence(fence_fd);
+}
+
+// Sync wait to close the previous fd
+void BlitEngineC2d::SetReleaseFence(int fd) {
+ if (release_fence_fd_[current_blit_target_index_] >= 0) {
+ int ret = -1;
+ ret = sync_wait(release_fence_fd_[current_blit_target_index_], 1000);
+ if (ret < 0) {
+ DLOGE("sync_wait error! errno = %d, err str = %s", errno, strerror(errno));
+ }
+ close(release_fence_fd_[current_blit_target_index_]);
+ }
+ release_fence_fd_[current_blit_target_index_] = dup(fd);
+}
+
+bool BlitEngineC2d::BlitActive() {
+ return blit_active_;
+}
+
+void BlitEngineC2d::SetFrameDumpConfig(uint32_t count) {
+ dump_frame_count_ = count;
+ dump_frame_index_ = 0;
+}
+
+int BlitEngineC2d::Prepare(LayerStack *layer_stack) {
+ blit_target_start_index_ = 0;
+
+ uint32_t gpu_target_index = layer_stack->layer_count-1;
+ uint32_t i = INT(layer_stack->layer_count-1);
+
+ for (i = 0; i < layer_stack->layer_count; i++) {
+ Layer &layer = layer_stack->layers[i];
+ if (IsUBWCFormat(layer.input_buffer->format)) {
+ // UBWC is not currently supported
+ DLOGW("UBWC format found, cant support BLIT");
+ return -1;
+ }
+ if (layer.composition == kCompositionGPUTarget) {
+ // Need FBT size for allocating buffers
+ gpu_target_index = i;
+ break;
+ }
+ }
+
+ if ((layer_stack->layer_count-1) == gpu_target_index) {
+ // No blit target layer
+ return -1;
+ }
+
+ blit_target_start_index_ = ++i;
+ num_blit_target_= layer_stack->layer_count - blit_target_start_index_;
+
+ LayerBuffer *layer_buffer = layer_stack->layers[gpu_target_index].input_buffer;
+ int fbwidth = INT(layer_buffer->width);
+ int fbheight = INT(layer_buffer->height);
+ if ((fbwidth < 0) || (fbheight < 0)) {
+ return -1;
+ }
+
+ current_blit_target_index_ = (current_blit_target_index_ + 1) % kNumBlitTargetBuffers;
+ int k = blit_target_start_index_;
+
+ for (uint32_t j = 0; j < num_blit_target_; j++, k++) {
+ Layer &layer = layer_stack->layers[k];
+ LayerBuffer *layer_buffer = layer.input_buffer;
+
+ // Set the buffer height and width
+ layer_buffer->width = fbwidth;
+ layer_buffer->height = fbheight/3;
+
+ layer.plane_alpha = 0xFF;
+ layer.blending = kBlendingOpaque;
+ layer.composition = kCompositionBlitTarget;
+ }
+
+ return 0;
+}
+
+int BlitEngineC2d::PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
+ int status = 0;
+ uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1;
+ int target_width = 0;
+ int target_height = 0;
+ uint32_t processed_blit = 0;
+ LayerRect dst_rects[kMaxBlitTargetLayers];
+ bool blit_needed = false;
+
+ for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_); i--) {
+ Layer &layer = layer_stack->layers[i];
+ if (layer.composition != kCompositionBlit) {
+ continue;
+ }
+ blit_needed = true;
+ layer_stack->flags.attributes_changed = true;
+
+ Layer &blit_layer = layer_stack->layers[blit_target_start_index_ + processed_blit];
+ LayerRect &blit_src_rect = blit_layer.src_rect;
+ int width = INT(layer.dst_rect.right - layer.dst_rect.left);
+ int height = INT(layer.dst_rect.bottom - layer.dst_rect.top);
+ // TODO(user): FrameBuffer is assumed to be RGBA
+ AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, height,
+ INT(HAL_PIXEL_FORMAT_RGBA_8888), 0, width, height);
+
+ target_width = MAX(target_width, width);
+ target_height += height;
+
+ // Left will be zero always
+ dst_rects[processed_blit].top = FLOAT(target_height - height);
+ dst_rects[processed_blit].right = dst_rects[processed_blit].left +
+ (layer.dst_rect.right - layer.dst_rect.left);
+ dst_rects[processed_blit].bottom = (dst_rects[processed_blit].top +
+ (layer.dst_rect.bottom - layer.dst_rect.top));
+ blit_src_rect = dst_rects[processed_blit];
+ processed_blit++;
+ }
+
+ // Allocate a single buffer of RGBA8888 format
+ if (blit_needed && (AllocateBlitTargetBuffers(target_width, target_height,
+ HAL_PIXEL_FORMAT_RGBA_8888) < 0)) {
+ status = -1;
+ return status;
+ }
+
+ if (blit_needed) {
+ for (uint32_t j = 0; j < num_blit_target_; j++) {
+ Layer &layer = layer_stack->layers[j + content_list->numHwLayers];
+ private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+ // Set the fd information
+ if (layer.input_buffer) {
+ layer.input_buffer->width = target_width;
+ layer.input_buffer->height = target_height;
+ layer.input_buffer->planes[0].fd = target_buffer->fd;
+ layer.input_buffer->planes[0].offset = 0;
+ layer.input_buffer->planes[0].stride = target_buffer->width;
+ }
+ }
+ }
+
+ return status;
+}
+
+int BlitEngineC2d::Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
+ int fd = -1;
+ int status = 0;
+ bool hybrid_present = false;
+ uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1;
+ private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+ blit_active_ = false;
+
+ // if not Blit Targets return
+ for (uint32_t i = 0; i < num_app_layers; i++) {
+ Layer &layer = layer_stack->layers[i];
+ if (layer.composition == kCompositionHybrid || layer.composition == kCompositionBlit) {
+ hybrid_present = true;
+ }
+ }
+
+ if (!hybrid_present) {
+ return status;
+ }
+
+ // Clear blit target buffer
+ LayerRect clear_rect;
+ clear_rect.left = 0;
+ clear_rect.top = 0;
+ clear_rect.right = FLOAT(target_buffer->width);
+ clear_rect.bottom = FLOAT(target_buffer->height);
+ ClearTargetBuffer(target_buffer, clear_rect);
+
+ int copybit_layer_count = 0;
+ uint32_t processed_blit = 0;
+ for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_) &&
+ (status == 0); i--) {
+ Layer &layer = layer_stack->layers[i];
+ if (layer.composition != kCompositionBlit) {
+ continue;
+ }
+
+ for (uint32_t k = 0; k <= i; k++) {
+ Layer &bottom_layer = layer_stack->layers[k];
+ LayerBuffer *layer_buffer = bottom_layer.input_buffer;
+ // if layer below the blit layer does not intersect, ignore that layer
+ LayerRect inter_sect = Intersection(layer.dst_rect, bottom_layer.dst_rect);
+ if (bottom_layer.composition != kCompositionHybrid && !IsValid(inter_sect)) {
+ continue;
+ }
+ if (bottom_layer.composition == kCompositionGPU ||
+ bottom_layer.composition == kCompositionSDE ||
+ bottom_layer.composition == kCompositionGPUTarget) {
+ continue;
+ }
+
+ // For each layer marked as Hybrid, wait for acquire fence and then blit using the C2D
+ if (layer_buffer->acquire_fence_fd >= 0) {
+ // Wait for acquire fence on the App buffers.
+ if (sync_wait(layer_buffer->acquire_fence_fd, 1000) < 0) {
+ DLOGE("sync_wait error!! error no = %d err str = %s", errno, strerror(errno));
+ }
+ layer_buffer->acquire_fence_fd = -1;
+ }
+ hwc_layer_1_t *hwc_layer = &content_list->hwLayers[k];
+ LayerRect src_rect = bottom_layer.blit_regions.rect[processed_blit];
+ Layer &blit_layer = layer_stack->layers[blit_target_start_index_ + processed_blit];
+ LayerRect dest_rect = blit_layer.src_rect;
+ int ret_val = DrawRectUsingCopybit(hwc_layer, &bottom_layer, src_rect, dest_rect);
+ copybit_layer_count++;
+ if (ret_val < 0) {
+ copybit_layer_count = 0;
+ DLOGE("DrawRectUsingCopyBit failed");
+ status = -1;
+ break;
+ }
+ }
+ processed_blit++;
+ }
+
+ if (copybit_layer_count) {
+ blit_active_ = true;
+ blit_engine_c2d_->flush_get_fence(blit_engine_c2d_, &fd);
+ }
+
+ if (blit_active_) {
+ // dump the render buffer
+ DumpBlitTargetBuffer(fd);
+
+ // Set the fd to the LayerStack BlitTargets fd
+ for (uint32_t k = blit_target_start_index_; k < layer_stack->layer_count; k++) {
+ Layer &layer = layer_stack->layers[k];
+ LayerBuffer *layer_buffer = layer.input_buffer;
+ layer_buffer->acquire_fence_fd = fd;
+ }
+ }
+
+ return status;
+}
+
+int BlitEngineC2d::DrawRectUsingCopybit(hwc_layer_1_t *hwc_layer, Layer *layer,
+ LayerRect blit_rect, LayerRect blit_dest_Rect) {
+ private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+ const private_handle_t *hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
+ LayerBuffer *layer_buffer = layer->input_buffer;
+
+ // Set the Copybit Source
+ copybit_image_t src;
+ src.handle = const_cast<native_handle_t *>(hwc_layer->handle);
+ src.w = hnd->width;
+ src.h = hnd->height;
+ src.base = reinterpret_cast<void *>(hnd->base);
+ src.format = hnd->format;
+ src.horiz_padding = 0;
+ src.vert_padding = 0;
+
+ // Copybit source rect
+ copybit_rect_t src_rect = {INT(blit_rect.left), INT(blit_rect.top), INT(blit_rect.right),
+ INT(blit_rect.bottom)};
+
+ // Copybit destination rect
+ copybit_rect_t dst_rect = {INT(blit_dest_Rect.left), INT(blit_dest_Rect.top),
+ INT(blit_dest_Rect.right), INT(blit_dest_Rect.bottom)};
+
+ // Copybit destination buffer
+ copybit_image_t dst;
+ dst.handle = static_cast<native_handle_t *>(target_buffer);
+ dst.w = ALIGN(target_buffer->width, 32);
+ dst.h = ALIGN((target_buffer->height), 32);
+ dst.base = reinterpret_cast<void *>(target_buffer->base);
+ dst.format = target_buffer->format;
+
+ // Copybit region is the destRect
+ LayerRect region_rect;
+ region_rect.left = FLOAT(dst_rect.l);
+ region_rect.top = FLOAT(dst_rect.t);
+ region_rect.right = FLOAT(dst_rect.r);
+ region_rect.bottom = FLOAT(dst_rect.b);
+
+ LayerRectArray region;
+ region.count = 1;
+ region.rect = ®ion_rect;
+ RegionIterator copybitRegion(region);
+ int acquireFd = layer_buffer->acquire_fence_fd;
+
+ // FRAMEBUFFER_WIDTH/HEIGHT for c2d is the target buffer w/h
+ blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_WIDTH,
+ target_buffer->width);
+ blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_HEIGHT,
+ target_buffer->height);
+ int transform = 0;
+ if (layer->transform.rotation) transform |= COPYBIT_TRANSFORM_ROT_90;
+ if (layer->transform.flip_horizontal) transform |= COPYBIT_TRANSFORM_FLIP_H;
+ if (layer->transform.flip_vertical) transform |= COPYBIT_TRANSFORM_FLIP_V;
+ blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_TRANSFORM, transform);
+ blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_PLANE_ALPHA, hwc_layer->planeAlpha);
+ blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_BLEND_MODE, hwc_layer->blending);
+ blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_DITHER,
+ (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
+ blit_engine_c2d_->set_sync(blit_engine_c2d_, acquireFd);
+ int err = blit_engine_c2d_->stretch(blit_engine_c2d_, &dst, &src, &dst_rect, &src_rect,
+ ©bitRegion);
+
+ if (err < 0) {
+ DLOGE("copybit stretch failed");
+ }
+
+ return err;
+}
+
+bool BlitEngineC2d::IsUBWCFormat(LayerBufferFormat format) {
+ switch (format) {
+ case kFormatRGBA8888Ubwc:
+ case kFormatRGBX8888Ubwc:
+ case kFormatRGB565Ubwc:
+ case kFormatYCbCr420SPVenusUbwc:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void BlitEngineC2d::DumpBlitTargetBuffer(int fd) {
+ if (!dump_frame_count_) {
+ return;
+ }
+
+ private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+
+ if (fd >= 0) {
+ int error = sync_wait(fd, 1000);
+ if (error < 0) {
+ DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+ return;
+ }
+ }
+
+ char dump_file_name[PATH_MAX];
+ size_t result = 0;
+ snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
+ "/blit_target_%d.raw", (dump_frame_index_));
+ FILE* fp = fopen(dump_file_name, "w+");
+ if (fp) {
+ result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
+ fclose(fp);
+ }
+ dump_frame_count_--;
+ dump_frame_index_++;
+}
+
+} // namespace sdm
+
diff --git a/sdm/libs/hwc/blit_engine_c2d.h b/sdm/libs/hwc/blit_engine_c2d.h
new file mode 100644
index 0000000..4034114
--- /dev/null
+++ b/sdm/libs/hwc/blit_engine_c2d.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+* Portions formerly licensed under Apache License, Version 2.0, are re licensed
+* under section 4 of Apache License, Version 2.0.
+
+* Copyright (C) 2010 The Android Open Source Project
+
+* Not a Contribution.
+
+* 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.
+*/
+
+/*! @file blit_engine.h
+ @brief Interface file for Blit based compositior.
+
+ @details The client can use this interface to get the blit composition done
+
+*/
+
+#include <hardware/hwcomposer.h>
+#include <core/layer_stack.h>
+#include <copybit.h>
+#include "blit_engine.h"
+
+#ifndef __BLIT_ENGINE_C2D_H__
+#define __BLIT_ENGINE_C2D_H__
+
+namespace sdm {
+
+// C2D Blit implemented by the client
+// This class implements the BlitEngine Interface which is used to get the
+// Blit composition using C2D
+class BlitEngineC2d : public BlitEngine {
+ public:
+ BlitEngineC2d();
+ virtual ~BlitEngineC2d();
+
+ virtual int Init();
+ virtual void DeInit();
+ virtual int Prepare(LayerStack *layer_stack);
+ virtual int PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack);
+ virtual int Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack);
+ virtual void PostCommit(LayerStack *layer_stack);
+ virtual bool BlitActive();
+ virtual void SetFrameDumpConfig(uint32_t count);
+
+
+ private:
+ static const uint32_t kNumBlitTargetBuffers = 3;
+
+ struct Range {
+ int current;
+ int end;
+ };
+
+ struct RegionIterator : public copybit_region_t {
+ explicit RegionIterator(LayerRectArray rect);
+ private:
+ static int iterate(copybit_region_t const *self, copybit_rect_t *rect);
+ LayerRectArray rect_array;
+ mutable Range r;
+ };
+
+ int AllocateBlitTargetBuffers(uint32_t width, uint32_t height, uint32_t format);
+ void FreeBlitTargetBuffers();
+ int ClearTargetBuffer(private_handle_t* hnd, const LayerRect& rect);
+ int DrawRectUsingCopybit(hwc_layer_1_t *hwc_layer, Layer *layer, LayerRect blit_rect,
+ LayerRect blit_dest_Rect);
+ void SetReleaseFence(int fence_fd);
+ bool IsUBWCFormat(LayerBufferFormat format);
+ void DumpBlitTargetBuffer(int fd);
+
+ copybit_device_t *blit_engine_c2d_;
+ private_handle_t *blit_target_buffer_[kNumBlitTargetBuffers];
+ uint32_t current_blit_target_index_;
+ int release_fence_fd_[kNumBlitTargetBuffers];
+ uint32_t num_blit_target_;
+ int blit_target_start_index_;
+ bool blit_active_;
+ uint32_t dump_frame_count_;
+ uint32_t dump_frame_index_;
+};
+
+} // namespace sdm
+
+#endif // __BLIT_ENGINE_C2D_H__
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index 3b10d7a..7b2766c 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -37,18 +37,19 @@
#include "hwc_display.h"
#include "hwc_debugger.h"
+#include "blit_engine_c2d.h"
#define __CLASS__ "HWCDisplay"
namespace sdm {
HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type,
- int id)
- : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL),
- flush_(false), dump_frame_count_(0), dump_frame_index_(0),
+ int id, bool needs_blit)
+ : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), needs_blit_(needs_blit),
+ display_intf_(NULL), flush_(false), dump_frame_count_(0), dump_frame_index_(0),
dump_input_layers_(false), swap_interval_zero_(false), framebuffer_config_(NULL),
display_paused_(false), use_metadata_refresh_rate_(false), metadata_refresh_rate_(0),
- boot_animation_completed_(false) {
+ boot_animation_completed_(false), use_blit_comp_(false), blit_engine_(NULL) {
}
int HWCDisplay::Init() {
@@ -73,6 +74,19 @@
return -EINVAL;
}
+ if (needs_blit_) {
+ blit_engine_ = new BlitEngineC2d();
+ if (!blit_engine_) {
+ DLOGI("Create Blit Engine C2D failed");
+ } else {
+ if (blit_engine_->Init() < 0) {
+ DLOGI("Blit Engine Init failed, Blit Composition will not be used!!");
+ delete blit_engine_;
+ blit_engine_= NULL;
+ }
+ }
+ }
+
return 0;
}
@@ -90,6 +104,12 @@
delete framebuffer_config_;
+ if (blit_engine_) {
+ blit_engine_->DeInit();
+ delete blit_engine_;
+ blit_engine_= NULL;
+ }
+
return 0;
}
@@ -231,6 +251,10 @@
dump_frame_index_ = 0;
dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0);
+ if (blit_engine_) {
+ blit_engine_->SetFrameDumpConfig(count);
+ }
+
DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
}
@@ -261,13 +285,25 @@
}
size_t num_hw_layers = content_list->numHwLayers;
+ uint32_t blit_target_count = 0;
+
+ if (needs_blit_ && blit_engine_) {
+ blit_target_count = kMaxBlitTargetLayers;
+ }
// Allocate memory for a) total number of layers b) buffer handle for each layer c) number of
// visible rectangles in each layer d) dirty rectangle for each layer
- size_t required_size = num_hw_layers * (sizeof(Layer) + sizeof(LayerBuffer));
- for (size_t i = 0; i < num_hw_layers; i++) {
- // visible rectangles + 1 dirty rectangle
- size_t num_rects = content_list->hwLayers[i].visibleRegionScreen.numRects + 1;
+ size_t required_size = (num_hw_layers + blit_target_count) *
+ (sizeof(Layer) + sizeof(LayerBuffer));
+
+ for (size_t i = 0; i < num_hw_layers + blit_target_count; i++) {
+ uint32_t num_visible_rects = 1;
+ if (i < num_hw_layers) {
+ num_visible_rects = INT32(content_list->hwLayers[i].visibleRegionScreen.numRects);
+ }
+
+ // visible rectangles + 1 dirty rectangle + blit rectangle
+ size_t num_rects = num_visible_rects + 1 + blit_target_count;
required_size += num_rects * sizeof(LayerRect);
}
@@ -281,7 +317,6 @@
// Allocate in multiple of kSizeSteps.
required_size = ROUND_UP(required_size, layer_stack_memory_.kSizeSteps);
-
layer_stack_memory_.raw = new uint8_t[required_size];
if (!layer_stack_memory_.raw) {
return -ENOMEM;
@@ -296,11 +331,16 @@
// Layer array address
layer_stack_ = LayerStack();
layer_stack_.layers = reinterpret_cast<Layer *>(current_address);
- layer_stack_.layer_count = static_cast<uint32_t>(num_hw_layers);
- current_address += num_hw_layers * sizeof(Layer);
+ layer_stack_.layer_count = INT32(num_hw_layers + blit_target_count);
+ current_address += (num_hw_layers + blit_target_count) * sizeof(Layer);
- for (size_t i = 0; i < num_hw_layers; i++) {
- hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+ for (size_t i = 0; i < num_hw_layers + blit_target_count; i++) {
+ uint32_t num_visible_rects = 1;
+ if (i < num_hw_layers) {
+ num_visible_rects =
+ static_cast<uint32_t>(content_list->hwLayers[i].visibleRegionScreen.numRects);
+ }
+
Layer &layer = layer_stack_.layers[i];
layer = Layer();
@@ -311,17 +351,25 @@
// Visible rectangle address
layer.visible_regions.rect = reinterpret_cast<LayerRect *>(current_address);
- layer.visible_regions.count = static_cast<uint32_t>(hwc_layer.visibleRegionScreen.numRects);
+ layer.visible_regions.count = num_visible_rects;
for (size_t i = 0; i < layer.visible_regions.count; i++) {
- *layer.visible_regions.rect = LayerRect();
+ layer.visible_regions.rect[i] = LayerRect();
}
- current_address += hwc_layer.visibleRegionScreen.numRects * sizeof(LayerRect);
+ current_address += num_visible_rects * sizeof(LayerRect);
// Dirty rectangle address
layer.dirty_regions.rect = reinterpret_cast<LayerRect *>(current_address);
layer.dirty_regions.count = 1;
*layer.dirty_regions.rect = LayerRect();
current_address += sizeof(LayerRect);
+
+ // Blit rectangle address
+ layer.blit_regions.rect = reinterpret_cast<LayerRect *>(current_address);
+ layer.blit_regions.count = blit_target_count;
+ for (size_t i = 0; i < layer.blit_regions.count; i++) {
+ layer.blit_regions.rect[i] = LayerRect();
+ }
+ current_address += layer.blit_regions.count * sizeof(LayerRect);
}
return 0;
@@ -422,6 +470,7 @@
int ret;
display_intf_->GetConfig(active_config_index, &active_config);
+ use_blit_comp_ = false;
// Configure each layer
for (size_t i = 0; i < num_hw_layers; i++) {
@@ -474,6 +523,18 @@
}
}
+ // Prepare the Blit Target
+ if (blit_engine_) {
+ int ret = blit_engine_->Prepare(&layer_stack_);
+ if (ret) {
+ // Blit engine cannot handle this layer stack, hence set the layer stack
+ // count to num_hw_layers
+ layer_stack_.layer_count -= kMaxBlitTargetLayers;
+ } else {
+ use_blit_comp_ = true;
+ }
+ }
+
// Configure layer stack
layer_stack_.flags.geometry_changed = ((content_list->flags & HWC_GEOMETRY_CHANGED) > 0);
@@ -497,7 +558,8 @@
Layer &layer = layer_stack_.layers[i];
LayerComposition composition = layer.composition;
- if (composition == kCompositionSDE) {
+ if ((composition == kCompositionSDE) || (composition == kCompositionHybrid) ||
+ (composition == kCompositionBlit)) {
hwc_layer.hints |= HWC_HINT_CLEAR_FB;
if (use_metadata_refresh_rate_ && layer.frame_rate > metadata_refresh_rate_) {
@@ -537,10 +599,23 @@
CommitLayerParams(&content_list->hwLayers[i], &layer_stack_.layers[i]);
}
- DisplayError error = display_intf_->Commit(&layer_stack_);
+ if (use_blit_comp_) {
+ status = blit_engine_->PreCommit(content_list, &layer_stack_);
+ if (status == 0) {
+ status = blit_engine_->Commit(content_list, &layer_stack_);
+ if (status != 0) {
+ DLOGE("Blit Comp Failed!");
+ }
+ }
+ }
+
+ DisplayError error = kErrorUndefined;
+ if (status == 0) {
+ error = display_intf_->Commit(&layer_stack_);
+ status = 0;
+ }
if (error != kErrorNone) {
DLOGE("Commit failed. Error = %d", error);
-
// To prevent surfaceflinger infinite wait, flush the previous frame during Commit() so that
// previous buffer and fences are released, and override the error.
flush_ = true;
@@ -561,6 +636,11 @@
}
}
+ // Set the release fence fd to the blit engine
+ if (use_blit_comp_ && blit_engine_->BlitActive()) {
+ blit_engine_->PostCommit(&layer_stack_);
+ }
+
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
Layer &layer = layer_stack_.layers[i];
@@ -595,7 +675,6 @@
}
}
-
if (!flush_) {
layer_stack_cache_.animating = layer_stack_.flags.animating;
@@ -663,7 +742,8 @@
for (uint32_t i = 0; i < layer_count; i++) {
Layer &layer = layer_stack_.layers[i];
- if (layer.composition == kCompositionGPUTarget) {
+ if (layer.composition == kCompositionGPUTarget ||
+ layer.composition == kCompositionBlitTarget) {
continue;
}
@@ -691,15 +771,15 @@
void HWCDisplay::SetComposition(const int32_t &source, LayerComposition *target) {
switch (source) {
case HWC_FRAMEBUFFER_TARGET: *target = kCompositionGPUTarget; break;
- default: *target = kCompositionSDE; break;
+ default: *target = kCompositionGPU; break;
}
}
void HWCDisplay::SetComposition(const int32_t &source, int32_t *target) {
switch (source) {
case kCompositionGPUTarget: *target = HWC_FRAMEBUFFER_TARGET; break;
- case kCompositionSDE: *target = HWC_OVERLAY; break;
- default: *target = HWC_FRAMEBUFFER; break;
+ case kCompositionGPU: *target = HWC_FRAMEBUFFER; break;
+ default: *target = HWC_OVERLAY; break;
}
}
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index 7df23dc..8882613 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -32,6 +32,8 @@
namespace sdm {
+class BlitEngine;
+
class HWCDisplay : public DisplayEventHandler {
public:
virtual int Init();
@@ -93,7 +95,8 @@
LayerStackCache() : layer_count(0), animating(false) { }
};
- HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id);
+ HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id,
+ bool needs_blit);
// DisplayEventHandler methods
virtual DisplayError VSync(const DisplayEventVSync &vsync);
@@ -130,6 +133,7 @@
hwc_procs_t const **hwc_procs_;
DisplayType type_;
int id_;
+ bool needs_blit_;
DisplayInterface *display_intf_;
LayerStackMemory layer_stack_memory_;
LayerStack layer_stack_;
@@ -152,6 +156,8 @@
bool NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list);
int PrepareLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer, uint32_t fps);
void CommitLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer);
+ bool use_blit_comp_;
+ BlitEngine *blit_engine_;
};
inline int HWCDisplay::Perform(uint32_t operation, ...) {
diff --git a/sdm/libs/hwc/hwc_display_external.cpp b/sdm/libs/hwc/hwc_display_external.cpp
index c3a07e7..d40602e 100644
--- a/sdm/libs/hwc/hwc_display_external.cpp
+++ b/sdm/libs/hwc/hwc_display_external.cpp
@@ -91,7 +91,7 @@
}
HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
- : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL) {
+ : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL, false) {
}
int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) {
diff --git a/sdm/libs/hwc/hwc_display_primary.cpp b/sdm/libs/hwc/hwc_display_primary.cpp
index 79deb25..8ac8389 100644
--- a/sdm/libs/hwc/hwc_display_primary.cpp
+++ b/sdm/libs/hwc/hwc_display_primary.cpp
@@ -84,7 +84,7 @@
}
HWCDisplayPrimary::HWCDisplayPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
- : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY) {
+ : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY, true) {
}
void HWCDisplayPrimary::ProcessBootAnimCompleted() {
diff --git a/sdm/libs/hwc/hwc_display_virtual.cpp b/sdm/libs/hwc/hwc_display_virtual.cpp
index 319c0ee..15da858 100644
--- a/sdm/libs/hwc/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc/hwc_display_virtual.cpp
@@ -98,7 +98,7 @@
}
HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
- : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL),
+ : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL, false),
dump_output_layer_(false), output_buffer_(NULL) {
}