1 /*
2 * Copyright Samsung Electronics Co.,LTD.
3 * Copyright (C) 2016 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <log/log.h>
19
20 #include <hardware/exynos/acryl.h>
21 #include <hardware/hwcomposer2.h>
22
23 #include "acrylic_internal.h"
24
AcrylicCanvas(Acrylic * compositor,canvas_type_t type)25 AcrylicCanvas::AcrylicCanvas(Acrylic *compositor, canvas_type_t type)
26 : mCompositor(compositor), mPixFormat(0), mNumBuffers(0), mFence(-1), mAttributes(ATTR_NONE),
27 mSettingFlags(0), mCanvasType(type)
28 {
29 // Initialize the image size to the possible smallest size
30 mImageDimension = compositor->getCapabilities().supportedMinSrcDimension();
31 }
32
~AcrylicCanvas()33 AcrylicCanvas::~AcrylicCanvas()
34 {
35 setFence(-1);
36 }
37
canvasTypeName(unsigned int type)38 static const char *canvasTypeName(unsigned int type)
39 {
40 static const char canvas_type_name[2][7] = {"source", "target"};
41
42 return canvas_type_name[type];
43 }
44
setImageDimension(int32_t width,int32_t height)45 bool AcrylicCanvas::setImageDimension(int32_t width, int32_t height)
46 {
47 if (((getSettingFlags() & SETTING_DIMENSION) != 0) &&
48 (width == mImageDimension.hori) && (height == mImageDimension.vert))
49 return true;
50
51 if (!getCompositor()) {
52 ALOGE("Trying to set image dimension to an orphaned layer");
53 return false;
54 }
55
56 unset(SETTING_DIMENSION);
57
58 const HW2DCapability &cap = getCompositor()->getCapabilities();
59
60 hw2d_coord_t minsize, maxsize;
61
62 if (mCanvasType == CANVAS_SOURCE) {
63 minsize = cap.supportedMinSrcDimension();
64 maxsize = cap.supportedMaxSrcDimension();
65 } else {
66 minsize = cap.supportedMinDstDimension();
67 maxsize = cap.supportedMaxDstDimension();
68 }
69
70 if ((width < minsize.hori) || (height < minsize.vert) || (width > maxsize.hori) || (height > maxsize.vert)) {
71 ALOGE("Invalid %s image size %dx%d (limit: %dx%d ~ %dx%d )",
72 canvasTypeName(mCanvasType), width, height,
73 minsize.hori, minsize.vert, maxsize.hori, maxsize.vert);
74 return false;
75 }
76
77 minsize = cap.supportedDimensionAlign();
78 if (!!(width & (minsize.hori - 1)) || !!(height & (minsize.vert - 1))) {
79 ALOGE("%s image size %dx%d violates alignment restriction %dx%d",
80 canvasTypeName(mCanvasType), width, height, minsize.hori, minsize.vert);
81 return false;
82 }
83
84 mImageDimension.hori = static_cast<int16_t>(width);
85 mImageDimension.vert = static_cast<int16_t>(height);
86
87 set(SETTING_DIMENSION | SETTING_DIMENSION_MODIFIED);
88
89 ALOGD_TEST("Configured dimension: %dx%d (type: %s)", width, height, canvasTypeName(mCanvasType));
90
91 return true;
92 }
93
setImageBuffer(int a,int r,int g,int b,uint32_t attr)94 bool AcrylicCanvas::setImageBuffer(int a, int r, int g, int b, uint32_t attr)
95 {
96 if (!getCompositor()) {
97 ALOGE("Trying to set buffer to an orphaned layer");
98 return false;
99 }
100
101 const HW2DCapability &cap = getCompositor()->getCapabilities();
102
103 if (((mCanvasType == CANVAS_SOURCE) && !cap.isFeatureSupported(HW2DCapability::FEATURE_SOLIDCOLOR)) ||
104 (mCanvasType == CANVAS_TARGET)) {
105 ALOGE("SolidColor is not supported for %s", canvasTypeName(mCanvasType));
106 return false;
107 }
108
109 setFence(-1);
110 mMemoryType = MT_EMPTY;
111 mNumBuffers = 0;
112
113 mAttributes = (attr & ATTR_ALL_MASK) | ATTR_SOLIDCOLOR;
114
115 set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
116
117 mSolidColor = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF));
118
119 return true;
120 }
121
setImageBuffer(int fd[MAX_HW2D_PLANES],size_t len[MAX_HW2D_PLANES],off_t offset[MAX_HW2D_PLANES],int num_buffers,int fence,uint32_t attr)122 bool AcrylicCanvas::setImageBuffer(int fd[MAX_HW2D_PLANES], size_t len[MAX_HW2D_PLANES], off_t offset[MAX_HW2D_PLANES],
123 int num_buffers, int fence, uint32_t attr)
124 {
125 if ((attr & ATTR_OTF) != 0)
126 return setImageOTFBuffer(attr);
127
128 if (!getCompositor()) {
129 ALOGE("Trying to set buffer to an orphaned layer");
130 return false;
131 }
132
133 const HW2DCapability &cap = getCompositor()->getCapabilities();
134 unsigned long alignmask = static_cast<unsigned long>(cap.supportedBaseAlign()) - 1;
135
136 if (num_buffers > MAX_HW2D_PLANES) {
137 ALOGE("Too many buffers %d are set passed to setImageBuffer(dmabuf)", num_buffers);
138 return false;
139 }
140
141 for (int i = 0; i < num_buffers; i++) {
142 if ((offset[i] < 0) || (static_cast<size_t>(offset[i]) >= len[i])) {
143 ALOGE("Too large offset %ld for length %zu of buffer[%d]", offset[i], len[i], i);
144 return false;
145 }
146
147 if ((offset[i] & alignmask) != 0) {
148 ALOGE("Alignment of offset %#lx of buffer[%d] violates the alignment of %#lx",
149 offset[i], i, alignmask + 1);
150 return false;
151 }
152 }
153
154 for (int i = 0; i < num_buffers; i++) {
155 m.mBufferFd[i] = fd[i];
156 mBufferLength[i] = len[i];
157 mBufferOffset[i] = offset[i];
158 ALOGD_TEST("Configured buffer[%d]: fd %d, len %zu, offset %u (type: %s)",
159 i, m.mBufferFd[i], mBufferLength[i], mBufferOffset[i],
160 canvasTypeName(mCanvasType));
161 }
162
163 ALOGE_IF((attr & ~ATTR_ALL_MASK) != 0,
164 "Configured unsupported attribute %#x to setImageBuffer(dmabuf))", attr);
165
166 setFence(fence);
167 mMemoryType = MT_DMABUF;
168 mNumBuffers = num_buffers;
169
170 mAttributes = attr & ATTR_ALL_MASK;
171 ALOGD_TEST("Configured buffer: fence %d, type %d, count %d, attr %#x (type: %s)",
172 mFence, mMemoryType, mNumBuffers, mAttributes, canvasTypeName(mCanvasType));
173
174 set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
175
176 return true;
177 }
178
setImageBuffer(void * addr[MAX_HW2D_PLANES],size_t len[MAX_HW2D_PLANES],int num_buffers,uint32_t attr)179 bool AcrylicCanvas::setImageBuffer(void *addr[MAX_HW2D_PLANES], size_t len[MAX_HW2D_PLANES],
180 int num_buffers, uint32_t attr)
181 {
182 if ((attr & ATTR_OTF) != 0)
183 return setImageOTFBuffer(attr);
184
185 if (!getCompositor()) {
186 ALOGE("Trying to set buffer to an orphaned layer");
187 return false;
188 }
189
190 const HW2DCapability &cap = getCompositor()->getCapabilities();
191 unsigned long alignmask = static_cast<unsigned long>(cap.supportedBaseAlign()) - 1;
192
193 if (num_buffers > MAX_HW2D_PLANES) {
194 ALOGE("Too many buffers %d are set passed to setImageBuffer(userptr)", num_buffers);
195 return false;
196 }
197
198 for (int i = 0; i < num_buffers; i++) {
199 if ((reinterpret_cast<unsigned long>(addr[i]) & alignmask) != 0) {
200 ALOGE("Alignment of address %p of buffer[%d] violates the alignment of %#lx",
201 addr[i], i, alignmask + 1);
202 return false;
203 }
204 }
205
206 for (int i = 0; i < num_buffers; i++) {
207 m.mBufferAddr[i] = addr[i];
208 mBufferLength[i] = len[i];
209 mBufferOffset[i] = 0;
210 ALOGD_TEST("Configured buffer[%d]: addr %p, len %zu, offset %u (type: %s)",
211 i, m.mBufferAddr[i], mBufferLength[i], mBufferOffset[i],
212 canvasTypeName(mCanvasType));
213 }
214
215 ALOGE_IF((attr & ~ATTR_ALL_MASK) != 0,
216 "Configured unsupported attribute %#x to setImageBuffer(userptr))", attr);
217
218 setFence(-1);
219 mMemoryType = MT_USERPTR;
220 mNumBuffers = num_buffers;
221
222 mAttributes = attr & ATTR_ALL_MASK;
223
224 ALOGD_TEST("Configured buffer: fence %d, type %d, count %d, attr %#x (type: %s)",
225 mFence, mMemoryType, mNumBuffers, mAttributes, canvasTypeName(mCanvasType));
226
227 set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
228
229 return true;
230 }
231
setImageOTFBuffer(uint32_t attr)232 bool AcrylicCanvas::setImageOTFBuffer(uint32_t attr)
233 {
234 if (!getCompositor()) {
235 ALOGE("Trying to set buffer to an orphaned layer");
236 return false;
237 }
238
239 const HW2DCapability &cap = getCompositor()->getCapabilities();
240
241 if (((mCanvasType == CANVAS_SOURCE) && !cap.isFeatureSupported(HW2DCapability::FEATURE_OTF_READ)) ||
242 ((mCanvasType == CANVAS_TARGET) && !cap.isFeatureSupported(HW2DCapability::FEATURE_OTF_WRITE))) {
243 ALOGE("OTF is not supported for %s", canvasTypeName(mCanvasType));
244 return false;
245 }
246
247 setFence(-1);
248 mMemoryType = MT_EMPTY;
249 mNumBuffers = 0;
250
251 mAttributes = (attr & ATTR_ALL_MASK) | ATTR_OTF;
252
253 set(SETTING_BUFFER | SETTING_BUFFER_MODIFIED);
254
255 return true;
256 }
257
setImageType(uint32_t fmt,int dataspace)258 bool AcrylicCanvas::setImageType(uint32_t fmt, int dataspace)
259 {
260 if (((getSettingFlags() & SETTING_TYPE) != 0) &&
261 (mPixFormat == fmt) && (mDataSpace == dataspace))
262 return true;
263
264 if (!getCompositor()) {
265 ALOGE("Trying to set image type to an orphaned layer");
266 return false;
267 }
268
269 unset(SETTING_TYPE);
270
271 const HW2DCapability &cap = getCompositor()->getCapabilities();
272
273 if (!cap.isFormatSupported(fmt)) {
274 ALOGE("fmt %#x is not supported.", fmt);
275 return false;
276 }
277
278 if (!cap.isDataspaceSupported(dataspace)) {
279 ALOGE("dataspace %d is not supported.", dataspace);
280 return false;
281 }
282
283 mPixFormat = fmt;
284 mDataSpace = dataspace;
285
286 ALOGD_TEST("Configured format %#x and dataspace %#x (type: %s)",
287 mPixFormat, mDataSpace, canvasTypeName(mCanvasType));
288
289 set(SETTING_TYPE | SETTING_TYPE_MODIFIED);
290
291 return true;
292 }
293
setFence(int fence)294 void AcrylicCanvas::setFence(int fence)
295 {
296 if (mFence >= 0)
297 close(mFence);
298
299 mFence = fence;
300 }
301
AcrylicLayer(Acrylic * compositor)302 AcrylicLayer::AcrylicLayer(Acrylic *compositor)
303 : AcrylicCanvas(compositor), mTransitData(nullptr), mBlendingMode(HWC_BLENDING_NONE),
304 mTransform(0), mZOrder(0), mMaxLuminance(100), mMinLuminance(0), mPlaneAlpha(255)
305 {
306 // Default settings:
307 // - Bleding mode: SRC_OVER
308 // - Rotaion: 0 degree
309 // - Flip: none
310 // - z-order: 0
311 // - plane alpha: 1 (255)
312 // - master display: [0.0000 nit ~ 100.0000 nit] (SDR)
313 // - target area: full area of the target image
314 mTargetRect.pos = {0, 0};
315 mTargetRect.size = {0, 0};
316 }
317
~AcrylicLayer()318 AcrylicLayer::~AcrylicLayer()
319 {
320 if (mCompositor)
321 mCompositor->removeLayer(this);
322 }
323
setCompositMode(uint32_t mode,uint8_t alpha,int z_order)324 bool AcrylicLayer::setCompositMode(uint32_t mode, uint8_t alpha, int z_order)
325 {
326 if (!getCompositor()) {
327 ALOGE("Trying to set compositing mode to an orphaned layer");
328 return false;
329 }
330
331 const HW2DCapability &cap = getCompositor()->getCapabilities();
332
333 bool okay = true;
334 switch (mode) {
335 case HWC_BLENDING_NONE:
336 case HWC2_BLEND_MODE_NONE:
337 if (!(cap.supportedCompositingMode() & HW2DCapability::BLEND_SRC_COPY))
338 okay = false;
339 break;
340 case HWC_BLENDING_PREMULT:
341 case HWC2_BLEND_MODE_PREMULTIPLIED:
342 if (!(cap.supportedCompositingMode() & HW2DCapability::BLEND_SRC_OVER))
343 okay = false;
344 break;
345 case HWC_BLENDING_COVERAGE:
346 case HWC2_BLEND_MODE_COVERAGE:
347 if (!(cap.supportedCompositingMode() & HW2DCapability::BLEND_NONE))
348 okay = false;
349 break;
350 default:
351 ALOGE("Unknown bleding mode %#x", mode);
352 return false;
353 }
354
355 if (!okay) {
356 ALOGE("Unsupported blending mode %#x", mode);
357 return false;
358 }
359
360 mBlendingMode = mode;
361
362 mZOrder = z_order;
363 mPlaneAlpha = alpha;
364
365 ALOGD_TEST("Configured compositing mode: mode %d, z-order %d, alpha %d",
366 mBlendingMode, mZOrder, mPlaneAlpha);
367
368 return true;
369 }
370
371 #define ALOGE_RECT(msg, title, rect) ALOGE(msg ": (%d, %d) -> (%d, %d)", title, (rect).left, (rect).top, (rect).right, (rect).bottom);
372
setCompositArea(hwc_rect_t & src_area,hwc_rect_t & out_area,uint32_t transform,uint32_t attr)373 bool AcrylicLayer::setCompositArea(hwc_rect_t &src_area, hwc_rect_t &out_area, uint32_t transform, uint32_t attr)
374 {
375 if (!getCompositor()) {
376 ALOGE("Trying to set compositing area to an orphaned layer");
377 return false;
378 }
379
380 const HW2DCapability &cap = getCompositor()->getCapabilities();
381 hw2d_coord_t limit;
382
383 // 1. Transform capability check
384 if ((transform & cap.getHWCTransformMask()) != transform) {
385 ALOGE("transform value %#x is not supported: supported transform mask: %#x",
386 transform, cap.getHWCTransformMask());
387 return false;
388 }
389
390 // 2. Source area verification
391 int32_t val = src_area.left | src_area.top | src_area.right | src_area.bottom;
392 if (val < 0) {
393 ALOGE_RECT("Negative position in the %s area", "source", src_area);
394 return false;
395 }
396
397 if ((src_area.left >= src_area.right) || (src_area.top >= src_area.bottom)) {
398 ALOGE_RECT("Invalid %s position and area", "source", out_area);
399 return false;
400 }
401
402 limit = cap.supportedMinSrcDimension();
403 if ((get_width(src_area) < limit.hori) || (get_height(src_area) < limit.vert)) {
404 ALOGE_RECT("Too small %s area", "source", src_area);
405 return false;
406 }
407
408 limit = getImageDimension();
409 if ((src_area.right > limit.hori) || (src_area.bottom > limit.vert)) {
410 ALOGE_RECT("Too large %s area", "source", src_area);
411 ALOGE(" Image full size: %dx%d", limit.hori, limit.vert);
412 return false;
413 }
414
415 // 3. Target area verification
416 val = out_area.left | out_area.top | out_area.right | out_area.bottom;
417 if (val != 0) {
418 // The following checks on the target area are deferred to commit()
419 // - if area size is larger than the limit
420 // - if the right/bottom position exceed the limit
421 if (val < 0) {
422 ALOGE_RECT("Negative position in the %s area", "target", out_area);
423 return false;
424 }
425
426 if ((out_area.left >= out_area.right) || (out_area.top >= out_area.bottom)) {
427 ALOGE_RECT("Invalid %s position and area", "target", out_area);
428 return false;
429 }
430
431 limit = cap.supportedMinDstDimension();
432 if ((get_width(out_area) < limit.hori) || (get_height(out_area) < limit.vert)) {
433 ALOGE_RECT("too small %s area", "target", out_area);
434 return false;
435 }
436
437 // 4. Scaling limit verification if target area is specified
438 hw2d_coord_t src_xy, out_xy;
439
440 src_xy.hori = get_width(src_area);
441 src_xy.vert = get_height(src_area);
442 out_xy.hori = get_width(out_area);
443 out_xy.vert = get_height(out_area);
444
445 bool scaling_ok = !(attr & ATTR_NORESAMPLING)
446 ? cap.supportedResampling(src_xy, out_xy, transform)
447 : cap.supportedResizing(src_xy, out_xy, transform);
448
449 if (!scaling_ok) {
450 ALOGE("Unsupported scaling from %dx%d@(%d,%d) --> %dx%d@(%d,%d) with transform %d and attr %#x",
451 get_width(src_area), get_height(src_area), src_area.left, src_area.top,
452 get_width(out_area), get_height(out_area), out_area.left, out_area.top, transform, attr);
453 return false;
454 }
455 }
456
457 mTargetRect.pos.hori = static_cast<int16_t>(out_area.left);
458 mTargetRect.pos.vert = static_cast<int16_t>(out_area.top);
459 mTargetRect.size.hori = static_cast<int16_t>(get_width(out_area));
460 mTargetRect.size.vert = static_cast<int16_t>(get_height(out_area));
461
462 mImageRect.pos.hori = static_cast<int16_t>(src_area.left);
463 mImageRect.pos.vert = static_cast<int16_t>(src_area.top);
464 mImageRect.size.hori = static_cast<int16_t>(get_width(src_area));
465 mImageRect.size.vert = static_cast<int16_t>(get_height(src_area));
466
467 mTransform = transform;
468 mCompositAttr = attr & ATTR_ALL_MASK;
469
470 ALOGD_TEST("Configured area: %dx%d@%dx%d -> %dx%d@%dx%d, transform: %d, attr: %#x",
471 mImageRect.size.hori, mImageRect.size.vert, mImageRect.pos.hori, mImageRect.pos.vert,
472 mTargetRect.size.hori, mTargetRect.size.vert, mTargetRect.pos.hori, mTargetRect.pos.vert,
473 mTransform, mCompositAttr);
474
475 return true;
476 }
477
setImageDimension(int32_t width,int32_t height)478 bool AcrylicLayer::setImageDimension(int32_t width, int32_t height)
479 {
480 if (!AcrylicCanvas::setImageDimension(width, height))
481 return false;
482
483 // NOTE: the crop area should be initialized with the new image size
484 mImageRect.pos = {0, 0};
485 mImageRect.size = getImageDimension();
486
487 ALOGD_TEST("Reset the image rect to %dx%d@0x0", mImageRect.size.hori, mImageRect.size.vert);
488
489 return true;
490 }
491
setMasterDisplayLuminance(uint16_t min,uint16_t max)492 void AcrylicLayer::setMasterDisplayLuminance(uint16_t min, uint16_t max)
493 {
494 if (max < 100) {
495 ALOGE("Too small max display luminance %u.", max);
496 } else {
497 mMaxLuminance = max;
498 mMinLuminance = min;
499 }
500 }
501
importLayer(AcrylicLayer & other,bool inherit_transform)502 void AcrylicLayer::importLayer(AcrylicLayer &other, bool inherit_transform)
503 {
504 // Data to import
505 // - image size and the image rect
506 // - buffer and its attributes
507 // - acquire fence (the fence of @other should be invalidated)
508 // - pixel format, color space
509 // - geometric transformation if @inherit_transform is true
510 // Data NOT to import
511 // - the target rect
512 // - the blending attribute
513 // - z-order and plane alpha
514 hw2d_coord_t xy = other.getImageDimension();
515 AcrylicCanvas::setImageDimension(xy.hori, xy.vert);
516 setImageType(other.getFormat(), other.getDataspace());
517
518 uint32_t attr = ATTR_NONE;
519 if (other.isProtected())
520 attr |= ATTR_PROTECTED;
521 if (other.isCompressed())
522 attr |= ATTR_COMPRESSED;
523
524 if (other.getBufferType() == MT_DMABUF) {
525 int fd[3];
526 off_t off[3];
527 size_t len[3];
528
529 for (unsigned int i = 0; i < other.getBufferCount(); i++) {
530 fd[i] = other.getDmabuf(i);
531 off[i] = other.getOffset(i);
532 len[i] = other.getBufferLength(i);
533 }
534
535 setImageBuffer(fd, len, off, other.getBufferCount(), other.getFence(), attr);
536 } else {
537 void *addr[3];
538 size_t len[3];
539
540 for (unsigned int i = 0; i < other.getBufferCount(); i++) {
541 addr[i] = other.getUserptr(i);
542 len[i] = other.getBufferLength(i);
543 }
544
545 setImageBuffer(addr, len, other.getBufferCount(), attr);
546 }
547
548 other.clearFence();
549 mImageRect = other.mImageRect;
550 if (inherit_transform)
551 mTransform = other.mTransform;
552 }
553