/*
* Copyright 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.
*/
#ifndef ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
#ifndef LOG_TAG
#warn "IComposerCommandBuffer.h included without LOG_TAG"
#endif
#undef LOG_NDEBUG
#define LOG_NDEBUG 0
#include <algorithm>
#include <limits>
#include <memory>
#include <vector>
#include <inttypes.h>
#include <string.h>
#include <android/hardware/graphics/composer/2.1/IComposer.h>
#include <log/log.h>
#include <sync/sync.h>
#include <fmq/MessageQueue.h>
namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_1 {
using android::hardware::graphics::common::V1_0::ColorTransform;
using android::hardware::graphics::common::V1_0::Dataspace;
using android::hardware::graphics::common::V1_0::Transform;
using android::hardware::MessageQueue;
using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>;
// This class helps build a command queue. Note that all sizes/lengths are in
// units of uint32_t's.
class CommandWriterBase {
public:
CommandWriterBase(uint32_t initialMaxSize)
: mDataMaxSize(initialMaxSize)
{
mData = std::make_unique<uint32_t[]>(mDataMaxSize);
reset();
}
virtual ~CommandWriterBase()
{
reset();
}
void reset()
{
mDataWritten = 0;
mCommandEnd = 0;
// handles in mDataHandles are owned by the caller
mDataHandles.clear();
// handles in mTemporaryHandles are owned by the writer
for (auto handle : mTemporaryHandles) {
native_handle_close(handle);
native_handle_delete(handle);
}
mTemporaryHandles.clear();
}
IComposerClient::Command getCommand(uint32_t offset)
{
uint32_t val = (offset < mDataWritten) ? mData[offset] : 0;
return static_cast<IComposerClient::Command>(val &
static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK));
}
bool writeQueue(bool* outQueueChanged, uint32_t* outCommandLength,
hidl_vec<hidl_handle>* outCommandHandles)
{
// write data to queue, optionally resizing it
if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) {
if (!mQueue->write(mData.get(), mDataWritten)) {
ALOGE("failed to write commands to message queue");
return false;
}
*outQueueChanged = false;
} else {
auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize);
if (!newQueue->isValid() ||
!newQueue->write(mData.get(), mDataWritten)) {
ALOGE("failed to prepare a new message queue ");
return false;
}
mQueue = std::move(newQueue);
*outQueueChanged = true;
}
*outCommandLength = mDataWritten;
outCommandHandles->setToExternal(
const_cast<hidl_handle*>(mDataHandles.data()),
mDataHandles.size());
return true;
}
const MQDescriptorSync<uint32_t>* getMQDescriptor() const
{
return (mQueue) ? mQueue->getDesc() : nullptr;
}
static constexpr uint16_t kSelectDisplayLength = 2;
void selectDisplay(Display display)
{
beginCommand(IComposerClient::Command::SELECT_DISPLAY,
kSelectDisplayLength);
write64(display);
endCommand();
}
static constexpr uint16_t kSelectLayerLength = 2;
void selectLayer(Layer layer)
{
beginCommand(IComposerClient::Command::SELECT_LAYER,
kSelectLayerLength);
write64(layer);
endCommand();
}
static constexpr uint16_t kSetErrorLength = 2;
void setError(uint32_t location, Error error)
{
beginCommand(IComposerClient::Command::SET_ERROR, kSetErrorLength);
write(location);
writeSigned(static_cast<int32_t>(error));
endCommand();
}
static constexpr uint32_t kPresentOrValidateDisplayResultLength = 1;
void setPresentOrValidateResult(uint32_t state) {
beginCommand(IComposerClient::Command::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT, kPresentOrValidateDisplayResultLength);
write(state);
endCommand();
}
void setChangedCompositionTypes(const std::vector<Layer>& layers,
const std::vector<IComposerClient::Composition>& types)
{
size_t totalLayers = std::min(layers.size(), types.size());
size_t currentLayer = 0;
while (currentLayer < totalLayers) {
size_t count = std::min(totalLayers - currentLayer,
static_cast<size_t>(kMaxLength) / 3);
beginCommand(
IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES,
count * 3);
for (size_t i = 0; i < count; i++) {
write64(layers[currentLayer + i]);
writeSigned(static_cast<int32_t>(types[currentLayer + i]));
}
endCommand();
currentLayer += count;
}
}
void setDisplayRequests(uint32_t displayRequestMask,
const std::vector<Layer>& layers,
const std::vector<uint32_t>& layerRequestMasks)
{
size_t totalLayers = std::min(layers.size(),
layerRequestMasks.size());
size_t currentLayer = 0;
while (currentLayer < totalLayers) {
size_t count = std::min(totalLayers - currentLayer,
static_cast<size_t>(kMaxLength - 1) / 3);
beginCommand(IComposerClient::Command::SET_DISPLAY_REQUESTS,
1 + count * 3);
write(displayRequestMask);
for (size_t i = 0; i < count; i++) {
write64(layers[currentLayer + i]);
write(static_cast<int32_t>(layerRequestMasks[currentLayer + i]));
}
endCommand();
currentLayer += count;
}
}
static constexpr uint16_t kSetPresentFenceLength = 1;
void setPresentFence(int presentFence)
{
beginCommand(IComposerClient::Command::SET_PRESENT_FENCE,
kSetPresentFenceLength);
writeFence(presentFence);
endCommand();
}
void setReleaseFences(const std::vector<Layer>& layers,
const std::vector<int>& releaseFences)
{
size_t totalLayers = std::min(layers.size(), releaseFences.size());
size_t currentLayer = 0;
while (currentLayer < totalLayers) {
size_t count = std::min(totalLayers - currentLayer,
static_cast<size_t>(kMaxLength) / 3);
beginCommand(IComposerClient::Command::SET_RELEASE_FENCES,
count * 3);
for (size_t i = 0; i < count; i++) {
write64(layers[currentLayer + i]);
writeFence(releaseFences[currentLayer + i]);
}
endCommand();
currentLayer += count;
}
}
static constexpr uint16_t kSetColorTransformLength = 17;
void setColorTransform(const float* matrix, ColorTransform hint)
{
beginCommand(IComposerClient::Command::SET_COLOR_TRANSFORM,
kSetColorTransformLength);
for (int i = 0; i < 16; i++) {
writeFloat(matrix[i]);
}
writeSigned(static_cast<int32_t>(hint));
endCommand();
}
void setClientTarget(uint32_t slot, const native_handle_t* target,
int acquireFence, Dataspace dataspace,
const std::vector<IComposerClient::Rect>& damage)
{
bool doWrite = (damage.size() <= (kMaxLength - 4) / 4);
size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0);
beginCommand(IComposerClient::Command::SET_CLIENT_TARGET, length);
write(slot);
writeHandle(target, true);
writeFence(acquireFence);
writeSigned(static_cast<int32_t>(dataspace));
// When there are too many rectangles in the damage region and doWrite
// is false, we write no rectangle at all which means the entire
// client target is damaged.
if (doWrite) {
writeRegion(damage);
}
endCommand();
}
static constexpr uint16_t kSetOutputBufferLength = 3;
void setOutputBuffer(uint32_t slot, const native_handle_t* buffer,
int releaseFence)
{
beginCommand(IComposerClient::Command::SET_OUTPUT_BUFFER,
kSetOutputBufferLength);
write(slot);
writeHandle(buffer, true);
writeFence(releaseFence);
endCommand();
}
static constexpr uint16_t kValidateDisplayLength = 0;
void validateDisplay()
{
beginCommand(IComposerClient::Command::VALIDATE_DISPLAY,
kValidateDisplayLength);
endCommand();
}
static constexpr uint16_t kPresentOrValidateDisplayLength = 0;
void presentOrvalidateDisplay()
{
beginCommand(IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY,
kPresentOrValidateDisplayLength);
endCommand();
}
static constexpr uint16_t kAcceptDisplayChangesLength = 0;
void acceptDisplayChanges()
{
beginCommand(IComposerClient::Command::ACCEPT_DISPLAY_CHANGES,
kAcceptDisplayChangesLength);
endCommand();
}
static constexpr uint16_t kPresentDisplayLength = 0;
void presentDisplay()
{
beginCommand(IComposerClient::Command::PRESENT_DISPLAY,
kPresentDisplayLength);
endCommand();
}
static constexpr uint16_t kSetLayerCursorPositionLength = 2;
void setLayerCursorPosition(int32_t x, int32_t y)
{
beginCommand(IComposerClient::Command::SET_LAYER_CURSOR_POSITION,
kSetLayerCursorPositionLength);
writeSigned(x);
writeSigned(y);
endCommand();
}
static constexpr uint16_t kSetLayerBufferLength = 3;
void setLayerBuffer(uint32_t slot, const native_handle_t* buffer,
int acquireFence)
{
beginCommand(IComposerClient::Command::SET_LAYER_BUFFER,
kSetLayerBufferLength);
write(slot);
writeHandle(buffer, true);
writeFence(acquireFence);
endCommand();
}
void setLayerSurfaceDamage(
const std::vector<IComposerClient::Rect>& damage)
{
bool doWrite = (damage.size() <= kMaxLength / 4);
size_t length = (doWrite) ? damage.size() * 4 : 0;
beginCommand(IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE,
length);
// When there are too many rectangles in the damage region and doWrite
// is false, we write no rectangle at all which means the entire
// layer is damaged.
if (doWrite) {
writeRegion(damage);
}
endCommand();
}
static constexpr uint16_t kSetLayerBlendModeLength = 1;
void setLayerBlendMode(IComposerClient::BlendMode mode)
{
beginCommand(IComposerClient::Command::SET_LAYER_BLEND_MODE,
kSetLayerBlendModeLength);
writeSigned(static_cast<int32_t>(mode));
endCommand();
}
static constexpr uint16_t kSetLayerColorLength = 1;
void setLayerColor(IComposerClient::Color color)
{
beginCommand(IComposerClient::Command::SET_LAYER_COLOR,
kSetLayerColorLength);
writeColor(color);
endCommand();
}
static constexpr uint16_t kSetLayerCompositionTypeLength = 1;
void setLayerCompositionType(IComposerClient::Composition type)
{
beginCommand(IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE,
kSetLayerCompositionTypeLength);
writeSigned(static_cast<int32_t>(type));
endCommand();
}
static constexpr uint16_t kSetLayerDataspaceLength = 1;
void setLayerDataspace(Dataspace dataspace)
{
beginCommand(IComposerClient::Command::SET_LAYER_DATASPACE,
kSetLayerDataspaceLength);
writeSigned(static_cast<int32_t>(dataspace));
endCommand();
}
static constexpr uint16_t kSetLayerDisplayFrameLength = 4;
void setLayerDisplayFrame(const IComposerClient::Rect& frame)
{
beginCommand(IComposerClient::Command::SET_LAYER_DISPLAY_FRAME,
kSetLayerDisplayFrameLength);
writeRect(frame);
endCommand();
}
static constexpr uint16_t kSetLayerPlaneAlphaLength = 1;
void setLayerPlaneAlpha(float alpha)
{
beginCommand(IComposerClient::Command::SET_LAYER_PLANE_ALPHA,
kSetLayerPlaneAlphaLength);
writeFloat(alpha);
endCommand();
}
static constexpr uint16_t kSetLayerSidebandStreamLength = 1;
void setLayerSidebandStream(const native_handle_t* stream)
{
beginCommand(IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM,
kSetLayerSidebandStreamLength);
writeHandle(stream);
endCommand();
}
static constexpr uint16_t kSetLayerSourceCropLength = 4;
void setLayerSourceCrop(const IComposerClient::FRect& crop)
{
beginCommand(IComposerClient::Command::SET_LAYER_SOURCE_CROP,
kSetLayerSourceCropLength);
writeFRect(crop);
endCommand();
}
static constexpr uint16_t kSetLayerTransformLength = 1;
void setLayerTransform(Transform transform)
{
beginCommand(IComposerClient::Command::SET_LAYER_TRANSFORM,
kSetLayerTransformLength);
writeSigned(static_cast<int32_t>(transform));
endCommand();
}
void setLayerVisibleRegion(
const std::vector<IComposerClient::Rect>& visible)
{
bool doWrite = (visible.size() <= kMaxLength / 4);
size_t length = (doWrite) ? visible.size() * 4 : 0;
beginCommand(IComposerClient::Command::SET_LAYER_VISIBLE_REGION,
length);
// When there are too many rectangles in the visible region and
// doWrite is false, we write no rectangle at all which means the
// entire layer is visible.
if (doWrite) {
writeRegion(visible);
}
endCommand();
}
static constexpr uint16_t kSetLayerZOrderLength = 1;
void setLayerZOrder(uint32_t z)
{
beginCommand(IComposerClient::Command::SET_LAYER_Z_ORDER,
kSetLayerZOrderLength);
write(z);
endCommand();
}
protected:
void beginCommand(IComposerClient::Command command, uint16_t length)
{
if (mCommandEnd) {
LOG_FATAL("endCommand was not called before command 0x%x",
command);
}
growData(1 + length);
write(static_cast<uint32_t>(command) | length);
mCommandEnd = mDataWritten + length;
}
void endCommand()
{
if (!mCommandEnd) {
LOG_FATAL("beginCommand was not called");
} else if (mDataWritten > mCommandEnd) {
LOG_FATAL("too much data written");
mDataWritten = mCommandEnd;
} else if (mDataWritten < mCommandEnd) {
LOG_FATAL("too little data written");
while (mDataWritten < mCommandEnd) {
write(0);
}
}
mCommandEnd = 0;
}
void write(uint32_t val)
{
mData[mDataWritten++] = val;
}
void writeSigned(int32_t val)
{
memcpy(&mData[mDataWritten++], &val, sizeof(val));
}
void writeFloat(float val)
{
memcpy(&mData[mDataWritten++], &val, sizeof(val));
}
void write64(uint64_t val)
{
uint32_t lo = static_cast<uint32_t>(val & 0xffffffff);
uint32_t hi = static_cast<uint32_t>(val >> 32);
write(lo);
write(hi);
}
void writeRect(const IComposerClient::Rect& rect)
{
writeSigned(rect.left);
writeSigned(rect.top);
writeSigned(rect.right);
writeSigned(rect.bottom);
}
void writeRegion(const std::vector<IComposerClient::Rect>& region)
{
for (const auto& rect : region) {
writeRect(rect);
}
}
void writeFRect(const IComposerClient::FRect& rect)
{
writeFloat(rect.left);
writeFloat(rect.top);
writeFloat(rect.right);
writeFloat(rect.bottom);
}
void writeColor(const IComposerClient::Color& color)
{
write((color.r << 0) |
(color.g << 8) |
(color.b << 16) |
(color.a << 24));
}
// ownership of handle is not transferred
void writeHandle(const native_handle_t* handle, bool useCache)
{
if (!handle) {
writeSigned(static_cast<int32_t>((useCache) ?
IComposerClient::HandleIndex::CACHED :
IComposerClient::HandleIndex::EMPTY));
return;
}
mDataHandles.push_back(handle);
writeSigned(mDataHandles.size() - 1);
}
void writeHandle(const native_handle_t* handle)
{
writeHandle(handle, false);
}
// ownership of fence is transferred
void writeFence(int fence)
{
native_handle_t* handle = nullptr;
if (fence >= 0) {
handle = getTemporaryHandle(1, 0);
if (handle) {
handle->data[0] = fence;
} else {
ALOGW("failed to get temporary handle for fence %d", fence);
sync_wait(fence, -1);
close(fence);
}
}
writeHandle(handle);
}
native_handle_t* getTemporaryHandle(int numFds, int numInts)
{
native_handle_t* handle = native_handle_create(numFds, numInts);
if (handle) {
mTemporaryHandles.push_back(handle);
}
return handle;
}
static constexpr uint16_t kMaxLength =
std::numeric_limits<uint16_t>::max();
private:
void growData(uint32_t grow)
{
uint32_t newWritten = mDataWritten + grow;
if (newWritten < mDataWritten) {
LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32
", growing by %" PRIu32, mDataWritten, grow);
}
if (newWritten <= mDataMaxSize) {
return;
}
uint32_t newMaxSize = mDataMaxSize << 1;
if (newMaxSize < newWritten) {
newMaxSize = newWritten;
}
auto newData = std::make_unique<uint32_t[]>(newMaxSize);
std::copy_n(mData.get(), mDataWritten, newData.get());
mDataMaxSize = newMaxSize;
mData = std::move(newData);
}
uint32_t mDataMaxSize;
std::unique_ptr<uint32_t[]> mData;
uint32_t mDataWritten;
// end offset of the current command
uint32_t mCommandEnd;
std::vector<hidl_handle> mDataHandles;
std::vector<native_handle_t *> mTemporaryHandles;
std::unique_ptr<CommandQueueType> mQueue;
};
// This class helps parse a command queue. Note that all sizes/lengths are in
// units of uint32_t's.
class CommandReaderBase {
public:
CommandReaderBase() : mDataMaxSize(0)
{
reset();
}
bool setMQDescriptor(const MQDescriptorSync<uint32_t>& descriptor)
{
mQueue = std::make_unique<CommandQueueType>(descriptor, false);
if (mQueue->isValid()) {
return true;
} else {
mQueue = nullptr;
return false;
}
}
bool readQueue(uint32_t commandLength,
const hidl_vec<hidl_handle>& commandHandles)
{
if (!mQueue) {
return false;
}
auto quantumCount = mQueue->getQuantumCount();
if (mDataMaxSize < quantumCount) {
mDataMaxSize = quantumCount;
mData = std::make_unique<uint32_t[]>(mDataMaxSize);
}
if (commandLength > mDataMaxSize ||
!mQueue->read(mData.get(), commandLength)) {
ALOGE("failed to read commands from message queue");
return false;
}
mDataSize = commandLength;
mDataRead = 0;
mCommandBegin = 0;
mCommandEnd = 0;
mDataHandles.setToExternal(
const_cast<hidl_handle*>(commandHandles.data()),
commandHandles.size());
return true;
}
void reset()
{
mDataSize = 0;
mDataRead = 0;
mCommandBegin = 0;
mCommandEnd = 0;
mDataHandles.setToExternal(nullptr, 0);
}
protected:
bool isEmpty() const
{
return (mDataRead >= mDataSize);
}
bool beginCommand(IComposerClient::Command* outCommand,
uint16_t* outLength)
{
if (mCommandEnd) {
LOG_FATAL("endCommand was not called for last command");
}
constexpr uint32_t opcode_mask =
static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK);
constexpr uint32_t length_mask =
static_cast<uint32_t>(IComposerClient::Command::LENGTH_MASK);
uint32_t val = read();
*outCommand = static_cast<IComposerClient::Command>(
val & opcode_mask);
*outLength = static_cast<uint16_t>(val & length_mask);
if (mDataRead + *outLength > mDataSize) {
ALOGE("command 0x%x has invalid command length %" PRIu16,
*outCommand, *outLength);
// undo the read() above
mDataRead--;
return false;
}
mCommandEnd = mDataRead + *outLength;
return true;
}
void endCommand()
{
if (!mCommandEnd) {
LOG_FATAL("beginCommand was not called");
} else if (mDataRead > mCommandEnd) {
LOG_FATAL("too much data read");
mDataRead = mCommandEnd;
} else if (mDataRead < mCommandEnd) {
LOG_FATAL("too little data read");
mDataRead = mCommandEnd;
}
mCommandBegin = mCommandEnd;
mCommandEnd = 0;
}
uint32_t getCommandLoc() const
{
return mCommandBegin;
}
uint32_t read()
{
return mData[mDataRead++];
}
int32_t readSigned()
{
int32_t val;
memcpy(&val, &mData[mDataRead++], sizeof(val));
return val;
}
float readFloat()
{
float val;
memcpy(&val, &mData[mDataRead++], sizeof(val));
return val;
}
uint64_t read64()
{
uint32_t lo = read();
uint32_t hi = read();
return (static_cast<uint64_t>(hi) << 32) | lo;
}
IComposerClient::Color readColor()
{
uint32_t val = read();
return IComposerClient::Color{
static_cast<uint8_t>((val >> 0) & 0xff),
static_cast<uint8_t>((val >> 8) & 0xff),
static_cast<uint8_t>((val >> 16) & 0xff),
static_cast<uint8_t>((val >> 24) & 0xff),
};
}
// ownership of handle is not transferred
const native_handle_t* readHandle(bool* outUseCache)
{
const native_handle_t* handle = nullptr;
int32_t index = readSigned();
switch (index) {
case static_cast<int32_t>(IComposerClient::HandleIndex::EMPTY):
*outUseCache = false;
break;
case static_cast<int32_t>(IComposerClient::HandleIndex::CACHED):
*outUseCache = true;
break;
default:
if (static_cast<size_t>(index) < mDataHandles.size()) {
handle = mDataHandles[index].getNativeHandle();
} else {
ALOGE("invalid handle index %zu", static_cast<size_t>(index));
}
*outUseCache = false;
break;
}
return handle;
}
const native_handle_t* readHandle()
{
bool useCache;
return readHandle(&useCache);
}
// ownership of fence is transferred
int readFence()
{
auto handle = readHandle();
if (!handle || handle->numFds == 0) {
return -1;
}
if (handle->numFds != 1) {
ALOGE("invalid fence handle with %d fds", handle->numFds);
return -1;
}
int fd = dup(handle->data[0]);
if (fd < 0) {
ALOGW("failed to dup fence %d", handle->data[0]);
sync_wait(handle->data[0], -1);
fd = -1;
}
return fd;
}
private:
std::unique_ptr<CommandQueueType> mQueue;
uint32_t mDataMaxSize;
std::unique_ptr<uint32_t[]> mData;
uint32_t mDataSize;
uint32_t mDataRead;
// begin/end offsets of the current command
uint32_t mCommandBegin;
uint32_t mCommandEnd;
hidl_vec<hidl_handle> mDataHandles;
};
} // namespace V2_1
} // namespace composer
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H